CSLA .NET Framework
Return to CSLA .NET CS Errata

p 67 (URL correction)


At the bottom of the page is a link for the "Portal for My Data" article on MSDN. Microsoft has changed the URL for this article to

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet03262002.asp

 

(Updated 5/19/2006) View


p 57 (IBindingList interface)


In the first sentence of the IBindingList Interface section in the middle of the page, System.ComponentModel.BindingList should read System.ComponentModel.IBindingList.

(Updated 5/19/2006) View


p 287 (client-side DataPortal)


The code in the book caches a reference to ServicedDataPortal within the client-side DataPortal class. This is a problem when multiple root objects interact on the application server, as they all end up reusing that cached instance. Instead, a new instance of ServicedDataPortal should be created, as that is the behavior expected by COM+.

 

The code at the top of page 287 should read:

 

private static Server.ServicedDataPortal.DataPortal ServicedPortal

{

  get

  {

    return new Server.ServicedDataPortal.DataPortal();

  }

}

 

Of course the framework has evolved since the book, so in version 1.53 the code now looks like:

 

private static Server.ServicedDataPortal.DataPortal

  ServicedPortal(bool forceLocal)

{

  if(!forceLocal & _portalRemote)

  {

    // return remote instance

    return

      (Server.ServicedDataPortal.DataPortal)Activator.GetObject(

        typeof(Server.ServicedDataPortal.DataPortal),

        SERVICED_PORTAL_SERVER);

  }

  else

  {

    // return local instance

    return new Server.ServicedDataPortal.DataPortal();

  }

}

 

(Updated 1/20/2006) View


p 234 (BusinessCollectionBase)


The code at the top of page 234 should read:

    #region IsChild

           

    [NotUndoable()]

    bool _isChild = false;

 

    protected bool IsChild

    {

      get

      {

        return _isChild;

      }

    }

 

    protected void MarkAsChild()

    {

      _isChild = true;

    }

 

    #endregion

Note the addition of the NotUndoable attribute and the change in capitalization of _isChild.

(Updated 11/14/2005) View


p 374 (Figure 6-5)


The second property in Figure 6-5 says "Rate", but should be "Role".

(Updated 9/8/2005) View


p 479 (Save method)


The Save method is placed in the static Methods region, which can cause some confusion since it is not a static method.

No change is really required here, however the Save method could be put into the Data Access region to avoid the confusion.

(Updated 9/8/2005) View


p 739-740 (test console app)


The Main() method is shown as VB, but obviously should be C#:

 

using System;

using CSLA.BatchQueue.Server;

 

namespace BatchQueueTest

{

  class Class1

  {

    [STAThread]

    static void Main(string[] args)

    {

      Console.WriteLine("Server on thread {0}", AppDomain.GetCurrentThreadId());

      Console.WriteLine("Starting...");

      BatchQueueService.Start();

      Console.WriteLine("Started");

 

      Console.WriteLine("Press ENTER to end");

      Console.ReadLine();

 

      Console.WriteLine("Stopping...");

      BatchQueueService.Stop();

      Console.WriteLine("Stopped");

    }

  }

}

 

(Updated 8/3/2005) View


p 756-757 (GetField method)


the code
   return string.Empty();
 
should be
   return string.Empty;

(Updated 8/3/2005) View


p 677 (UpdateProject method)


The UpdateProject() method is missing these last two lines that do the actual update:
 
      project = (Project)project.Save();
 
      return project.ID.ToString();

(Updated 8/3/2005) View


p 603 (ProjectEdit.aspx)


The CompareValidators require an additional property be set to function properly: Type=Date

To allow the page to be canceled while the object is not valid, you need to add the following to the list of properties for btnCancel :
CausesValidation=false

(Updated 8/3/2005) View


p 737 (Dequeue method)


The declaration of msgID should initialize the variable to avoid a compiler warning:

string msgID = null;

 

(Updated 8/3/2005) View


p 700 (BatchQueue assembly)


The BatchQueue project needs references to all the CSLA framework assemblies, not just to CSLA.dll.

(Updated 8/3/2005) View


p 676 (UpdateProject method)


on page 676 the code
   if(data.Description != null)
       project.Started = data.Started;
 
Should be
     if(data.Started != null)
        project.Started = data.Started:

(Updated 8/3/2005) View


p 238 (diagram)


In the diagram on page 238, in the third column (after col.CancelEdit) DEL should be false, not true.

(Updated 8/3/2005) View


p 630 (control properties)


In Table 9-18 the third control listed should have ID=btnNewResource, not btnnewResource.

(Updated 4/29/2005) View


p 630 (ResourceEdit.aspx)


protected _resource As Resource
 
Should be
 
protected Resource _resource;

(Updated 4/29/2005) View


p 626 (configuring the DataGrid)


On page 626 in Table 9-17 the third row shows the Command name to be "Remove". This should be "Delete" instead.

(Updated 4/28/2005) View


p 230 (BusinessBase)


The "RulesCollection" property shown on this page should be named "BrokenRulesCollection":

 

    public BrokenRules.RulesCollection BrokenRulesCollection

    {

      get

      {

        return _brokenRules.BrokenRulesCollection;

      }

    }

 

(Updated 4/18/2005) View


p 259 (SmartDate)


The + and – operators of SmartDate are incorrect and should appear like this:

 

    static public SmartDate operator + (SmartDate d, TimeSpan t)

    {

      if (d.IsEmpty)

        return d;

      else

        return new SmartDate(d.Date + t, d.EmptyIsMin);

    }

 

    static public SmartDate operator - (SmartDate d, TimeSpan t)

    {

      if (d.IsEmpty)

        return d;

      else

        return new SmartDate(d.Date - t, d.EmptyIsMin);

    }

 

Additionally, the Equals method doesn’t properly handle empty SmartDate values and should appear like this:

 

    public override bool Equals(object o)

    {

      if (o is SmartDate)

      {

        SmartDate tmp = o as SmartDate;

        if (this.IsEmpty && tmp.IsEmpty)

          return true;

        else

          return _date.Equals(((SmartDate)o).Date);

      }

      else if(o is DateTime)

        return _date.Equals((DateTime)o);

      else

        return false;

    }

 

(Updated 3/8/2005) View


p 445,449,505,512 (Contains methods)


The text and code in the book illustrates how to override and/or overload the Contains method when creating your own business collections (such as ProjectResources and ResourceAssignments).

 

This is incorrect. The default Contains implementation in BusinessCollectionBase is sufficient for checking whether the collection contains specific child objects. The only requirement is that the child objects properly implement the Equals override as discussed in this errata.

 

Overloaded Contains implementations that accept object references as a parameter should not be included in business collection classes.

 

It is still valid for business collection classes to implement overloaded Contains methods that do comparisons on specific data values. For instance, ProjectResources should still include this:

 

    public bool Contains(string resourceID)

    {

      foreach(ProjectResource r in List)

        if(r.ResourceID == resourceID)

          return true;

      return false;

    }

 

This method doesn’t accept an object reference, but rather accepts a specific key value. This overload remains valid and should be used as appropriate.

 

This impacts some older errata regarding the Contains methods.

(Updated 2/23/2005) View


p 433 (Equals method)


The overload of the Equals method as described on p 433 is incorrect. To get the appropriate behavior for Equals, the following Equals implementation should be in the System Overrides region:

    public override bool Equals(object obj)

    {

      if (obj == null || obj.GetType() != this.GetType())

        return false;

      return Data == ((MyBusinessClass)obj).Data;

    }

This pre-supposes that the Data property exists on the object, and is the primary key or identifying value that should be used to compare the object.

This should replace the type-specific implementation of Equals shown in the book.

This change should be applied to the Project, Resource, ProjectResource and ResourceAssignment classes in the sample application as well. For instance, ProjectResource will have a single Equals method like this:

    public override bool Equals(object obj)

    {

      if (obj == null || obj.GetType() != this.GetType())

        return false;

      return _resourceID == ((ProjectResource)obj).ResourceID;

    }

(Updated 2/23/2005) View


p 347 (SafeDataReader)


In the SafeDataReader class the code for GetChar is incorrect:

    /// <summary>
    /// Gets a char value from the datareader.
    /// </summary>
    public char GetChar(int i)
    {
      if(_dataReader.IsDBNull(i))
        return char.MinValue;
      else
        return _dataReader.GetChar(i);
    }

Since SqlDataReader doesn't have a GetChar method this generates an error at runtime.

Code should be:

    /// <summary>
    /// Gets a char value from the datareader.
    /// </summary>
    public char GetChar(int i)
    {
      if(_dataReader.IsDBNull(i))
        return char.MinValue;
      else
      {
        char[] myChar = new char[1];
        _dataReader.GetChars(i, 0, myChar, 0, 1);
        return myChar[0];
      }
    }

(Updated 2/13/2005) View


p 632 (configuring the datagrid)


There are a couple incorrect elements in the table at the top of p 632.

In the second row, the Data Field should be "ProjectName", not "Name".

In the fifth row, the Command name should be "Delete", not "Remove".

(Updated 1/4/2005) View


pp 445, 449 (templates)


On pp 445 and 449 the Contains() methods should not be marked as overload.

(Updated 1/4/2005) View


p 311 (CSLA project)


After referencing the DataPortal assembly, the CSLA project also needs to reference System.EnterpriseServices.dll to compile. This should have been mentioned near the bottom of page 311.

(Updated 12/15/2004) View


p 545 (ProjectEdit form)


There's an extra call to DataBind in the btnSave_Click method.

The first call to DataBind (inside the try block) should be removed, leaving only the second call after the catch block.

Note that this code doesn't match the code in the download, because the code in the download actually closes the form when Save is clicked. However, the code in the download does also include the DataBind call in the try block. That call is unnecessary, because it triggers rebinding the display, which is then immediately closed.

(Updated 12/15/2004) View


p 105 (typo)


Criteria is misspelled in the diagram.

(Updated 12/8/2004) View


p 208 (BusinessBase)


The CancelEdit and ApplyEdit methods should not use the _bindingEdit variable, as it is added later in the chapter.

The ApplyEdit method should not use the _neverCommitted variable, as it is added later in the chapter.

(Updated 12/8/2004) View


p 527 (MainForm)


Near the top of the page the _main variable is incorrectly declared as _Main.

(Updated 12/8/2004) View


p 248 (ReadOnlyBase)


The ReadOnlyBase class should be marked as [Serializable()].

(Updated 12/8/2004) View


p 301 (server-side DataPortal)


throw e.InnerException(); should be throw e.InnerException; in both cases on this page.

(Updated 12/8/2004) View


p 258-259 (SmartDate)


The equality and inequality operators in the SmartDate class should read:

    static public bool operator == (SmartDate date1, SmartDate date2)

    {

      return Equals(date1, date2);

    }

 

    static public bool operator == (SmartDate date1, DateTime date2)

    {

      return Equals(date1, date2);

    }

 

    static public bool operator != (SmartDate date1, SmartDate date2)

    {

      return !Equals(date1, date2);

    }

 

    static public bool operator != (SmartDate date1, DateTime date2)

    {

      return !Equals(date1, date2);

    }

 

 

(Updated 12/6/2004) View


p 336 (BusinessIdentity)


The constructor for BusinessIdentity.Criteria should be public in scope:

 

      public Criteria(string username, string password)

 

 

(Updated 8/29/2004) View


p 191 (UndoableBase)


On page 191 at the top of  UndoableBase there should be three static variables declared:

 

    // variables containing type info for comparisons

    private static System.Type UndoableType  = typeof(UndoableBase);

    private static System.Type BusinessType  = typeof(BusinessBase);

    private static System.Type CollectionType =
      typeof(BusinessCollectionBase);

 

These variables are used throughout the rest of the class in the book when calling the IsSubclassOf method.

 

Alternately you can replace all occurances of UndoableType, BusinessType and CollectionType throughout the code with the appropriate typeof() statement. This second solution is what I opted to do in the final code available for download from my web site.

(Updated 8/16/2004) View


p 752 (ObjectAdapter)


An if() statement in ScanIList method has incorrect nesting. The corrected code is:

      if(ds.Count > 0)

      {

        // retrieve the first item from the list

        object obj = ds[0];

 

        if(obj is ValueType && obj.GetType().IsPrimitive)

        {

          // the value is a primitive value type

          _columns.Add("Value");

        }

        else

        {

          if(obj is string)

          {

            // the value is a simple string

            _columns.Add("Text");

          }

          else

          {

            // we have a complex Structure or object

            ScanObject(obj);

          }

        }

      }

 

(Updated 7/22/2004) View


p 490 (Assignment)


The code to load the _roles variable with data can lead to security errors in some cases. The variable is loaded with data in the static constructor of the Assignment class. It should be loaded in the Roles property on-demand:

//    static Assignment()

//    {

//      _roles = RoleList.GetList();

//    }

 

    public static RoleList Roles

    {

      get

      {

        if(_roles == null)

          _roles = RoleList.GetList();

        return _roles;

      }

    }

 

(Updated 7/22/2004) View


p 244 (BusinessCollectionBase)


There is an obscure bug with the way deleted child objects are removed from the collection in UndoChanges. This bug causes sporadic failure when a collection is data bound to a grid control and the user inserts and removes child objects, then cancels the form.

 

The corrected code goes in the loop that is processing the deleteList collection:

 

        if(child.EditLevelAdded > _editLevel)

        {

          // if item is below its point of addition, remove

          deletedList.Remove(child);

        }

        else

        {

          // if item is no longer deleted move back to main list

          if(!child.IsDeleted)

            UnDeleteChild(child);

        }

 

(Updated 7/22/2004) View


p 541 (Util.BindField)


The for() loop in the Util.BindField method is incorrect and should read:

 

for(int index = control.DataBindings.Count - 1; index >= 0; index--)

 

(Updated 7/16/2004) View


Chapter 4 (BusinessCollectionBase)


The reverse for loops in BusinessCollectionBase weren't processing the zero element. There are three lines that need to be changed.

In UndoChanges():

for(int index = List.Count - 1; index > 0; index--)

becomes

for(int index = List.Count - 1; index >= 0; index--)

and

for(int index = deletedList.Count - 1; index > 0; index--)

becomes

for(int index = deletedList.Count - 1; index >= 0; index--)

In AcceptChanges():

for(int index = deletedList.Count - 1; index > 0; index--)

becomes

for(int index = deletedList.Count - 1; index >= 0; index--)

 

(Updated 6/16/2004) View


p 259 (SmartDate)


The SmartDate.Add and Subtract methods should match the System.DateTime methods of the same names. This means they should appear as:

 

    /// <summary>

    /// Adds a TimeSpan onto the object.

    /// </summary>

    public DateTime Add(TimeSpan span)

    {

      return _date.Add(span);

    }

 

    /// <summary>

    /// Subtracts a TimeSpan from the object.

    /// </summary>

    public DateTime Subtract(TimeSpan span)

    {

      return _date.Subtract(span);

    }

 

    /// <summary>

    /// Subtracts a DateTime from the object.

    /// </summary>

    public TimeSpan Subtract(DateTime date)

    {

      return _date.Subtract(date);

    }

 

(Updated 6/10/2004) View



Return to CSLA .NET CS Errata