Tuesday, 16 November 2010

GridView fires a RowCommand event when the paging is triggered?

Yes, very odd behaviour this one.
I guess the assumption is that RowXXXXX events relate to Row events - selection, creation, deletion, editing. But RowCommand actually caters for any button that is clicked on a GridView.
Therefore paging controls are buttons, and therefore fire the RowCommand event with the CommandSource as "Page".
Therefore something like this will always fire both events:

<%@Page Language="C#" AutoEventWireup="true"%>
<script runat="server">
   1:  
   2: protected void Page_Load(object sender, EventArgs e)
   3: {
   4:      if(!IsPostBack)
   5:      {
   6:          ArrayList list = new ArrayList();
   7:          list.Add ( "Item1" );
   8:          list.Add ( "Item2" );
   9:          list.Add ( "Item3" );
  10:          list.Add ( "Item4" );
  11:     
  12:          this.GridView1.DataSource = list;
  13:          this.GridView1.DataBind();
  14:      }
  15: }
  16:  
  17: protected void RowCom( object sender, GridViewRowCommandArgs e)
  18: {
  19:      Page.Controls.Add ( new Label("Row_Command fired => CommandSource = " + e.CommandSource) );
  20: }
  21:  
  22: protected void Row_Index( object sender, GridViewPageIndexChangedCommandArgs e)
  23: {
  24:      Page.Controls.Add ( new Label("PageIndexChanged fired") );
  25: }
</script> <asp:GridView runat="server" ID="GridView1" OnRowCommand="RowCom" OnPageIndexChanging="Row_Index" EnablePaging="true" PageSize="2"> </asp:GridView>
Therefore, you have to ensure that in the RowCommand, that you only filter the events which you want, rather than assuming only row clicks will come through this event.

Friday, 30 July 2010

How to kill a process in SQL Server 2005 Process with ID –2

Recently, I encountered the problem where a transaction had been left open and therefore was causing issues with a specific table in the database. When looking at the SSMS in Maintenance –> Activity Monitor, the tables were being locked by Process ID –2. Normally you would kill processes by using the:

kill xx

e.g.

kill –2

Unfortunately, the kill command only allows you to kill process above 0. So how do you kill it?

The other way to kill processes is to use the GUID assigned to the process, which is found if you scroll slightly to the right. Like this





Although the GUID here is all zeroes (possibly because it is an internal process locking it), this is the GUID you use. So the command would look something like:

kill '4ab0d37b-566d-44ab-8396-4d35a53f955b'

After executing it in the Query Window, you should find the locks are released, but note that since you have killed the transaction, the data changes will be rolled back.

Tuesday, 22 June 2010

iPhone 0S4 update is taking too long to backup

So after downloading the iPhone OS 4, the backup begins – and well – is still around 5% after 3 1/2 hours.

I read a suggestion from the Apple Forums, to do the following:

  1. Cancel the backup
  2. Manually backup your iphone through itunes.
  3. Then restore iphone. An option will come up that says "restore and update".
  4. Iphone reboots after installation of os4. Then restore from backup in itunes

That process took about 30 minutes and I was done.

And I can verify that it does indeed!

Monday, 21 June 2010

Why and where is my XmlSerializer failing?

Overview

The XmlSerializer is an excellent utility to turn your classes into XML and vice versa very very easily. So long as you aren't using it on dynamically generated types, but are repeatedly on the same types, then the XML serializer is quite performant.

However, as great as the XmlSerializer is, I’ve found it a pain to debug. You have 2 choices:

  1. Look through the XML and find the invalid field
  2. Step through every property in the debugger for your class and find the property that is failing

Problem

When your XML document gets to the point of having hundreds of elements, this becomes a real problem. You’ll see output like this:

Writing to Application log: System.InvalidOperationException: There is an error in XML document (1, 10433). 
---> System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)
at System.Xml.XmlConvert.ToDecimal(String s)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderCustomer.Read3_Customer(Boolean isNullable, Boolean checkType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderCustomer.Read4_Customer()
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
at BusinessObjects.SerializationUtils.Deserialize[T](T& typeOfObject, String xml)
at WebServices.Customer.ImportCustomer(XmlDocument xml) in C:\MyWebServices\CustomerTest\Customer.asmx.cs:line 43

Now you see the problem. The XML indicates (1, 10433) , which would indicate my XML has be reduced to 1 line, trimming the spaces. and then column 10433. It turns out this is incorrect as my XML at this location was this:

</ns0:CreditLimit><ns0:LastPaymentDate>

..And obviously this is wrong. Totally valid XML wise, its just something cannot be parsed to a Decimal.


Solution


Since XmlSerializer generates physical code, which is then compiled on-the-fly, I was looking for a way to gain access to this file. Upon finding the location, Visual Studio 2008 doesn't realise that the file links to the PDB generated by the XmlSerializer compilation proces.


After a little digging, I've found that Scott Hanselman blogged about debugging the XmlSerializer serialization process in .NET, which is exactly what I was looking to do.


He says to add some entries to the related configuration file like:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="1" />
</switches>
</system.diagnostics>
...
</configuration>


This then allows you to open the file from the temporary directory C:\Documents And Settings\[user]\Local Settings\Temp after the new XmlSerializer(Type t) is executed. When the .Deserialize() method is called, you will find you can Step Into (!!) the code generated. The best thing about this, is that since the PDB is now linked together with the code, your stack traces are much more helpful:

.... as before but ....
at MS.XML.GeneratedAssembly.XmlSerializationReaderCustomer.Read3_Customer(Boolean isNullable, Boolean checkType)      in c:\Documents and Settings\ASPNET\Local Settings\Temp\dcvrxygb.0.cs:line 985
at MS.XML.GeneratedAssembly.XmlSerializationReaderCustomer.Read4_Customer()      in c:\Documents and Settings\ASPNET\Local Settings\Temp\dcvrxygb.0.cs:line 163
.........

Woohoo!! So we now have line numbers, and if we open up the source code we see .....


else if (.....)
{
o.@TaxRate = System.Xml.XmlConvert.ToDecimal(Reader.ReadElementString());
}
...


And we look at my XML element TaxRate (as they are a direct mapping and we find ....


<ns0:TaxRate>??</ns0:TaxRate>


Spot the problem ;-)

How to find out if there are items for an EnumerableRowCollection

Unfortunately, this class doesn’t have a .Count() method, so you have to do a horrible hack to find out if there are items.

I suppose you could implement it as an Extension method, but as it is, this is what you need to do:

// Create table and populate data
DataTable dt = new DataTable();
dt.Columns.Add("Column1",typeof(string));
dt.Rows.Add( new object[] { "sample1" });
 
// Filter by a non-existent field, so now dataRows is now an 
// EnumerableRowCollection with no rows
var dataRows = from row in dt.AsEnumerable()
               where row.Field<string>("Column1") eq "FAKE DATA"
               select row;
 
// This next line throws an InvalidOperationException 
//// DataTable filteredResults = dataRows.CopyToDataTable();   
 
// Instead, create a new IEnumerator and iterate through it manually.
IEnumerator iEnum = dataRows.GetEnumerator();
 
if(!iEnum.MoveNext())
{     
     ShowMessage("No data available");}
} 
else
{
     DataTable filteredResults = dataRows.CopyToDataTable();   
 
     //   More DataTable processing here ....     
     MyGridView1.DataSource = filteredResults;     
     MyGridView1.DataBind();}
}


It is nasty, but it works :-)