Showing posts with label CSLA. Show all posts
Showing posts with label CSLA. Show all posts

05 August 2010

Fixing CLSA property registration issues in child objects

AKA ‘avoiding the dreaded “Can not register property YourProperty after containing type (YourBaseType) has been instantiated” error message’

Somewhere between CSLA 3.0 en 3.6 a new way of registering properties has become into being:

// old skool CSLA
private string _oldProp = string.Empty;
public string OldProp
{
  get
  {return _oldProp;}	 
  set
  { if (value == null) value = string.Empty;
    if (!_oldProp.Equals(value))
    {
      _oldProp = value;
      PropertyHasChanged("OldProp");
    }
  }
}

//new skool CSLA
private static PropertyInfo NewPropProperty = 
  RegisterProperty(c => c.NewProp);
public string NewProp
{
	get { return GetProperty(NewPropProperty); }
	set { SetProperty(NewPropProperty, value); }
}

In CSLA 4.0 the last style is mandatory, so I started upgrading some objects (while currently using CSLA 3.8.3) in anticipation. So I upgraded my base object

using Csla;

namespace CslaInheritance
{
  public abstract class MyBaseClass : BusinessBase<MyBaseClass>
  {

    protected static PropertyInfo<string> MyProp1Property = 
        RegisterProperty<string>(c => c.MyProp1);
    public string MyProp1
    {
      get { return GetProperty(MyProp1Property); }
      set { SetProperty(MyProp1Property, value); }
    }

    protected static PropertyInfo<string> MyProp2Property = 
        RegisterProperty<string>(c => c.MyProp2);
    public string MyProp2
    {
      get { return GetProperty(MyProp2Property); }
      set { SetProperty(MyProp2Property, value); }
    }
  }
}
and then my child object
using Csla;

namespace CslaInheritance
{
  public abstract class MyConcreteClass1 : MyBaseClass
  {
    protected static PropertyInfo<string> ConcreteProp1Property = 
      RegisterProperty<string>(c => c.ConcreteProp1);
    public string ConcreteProp1
    {
      get { return GetProperty(ConcreteProp1Property); }
      set { SetProperty(ConcreteProp1Property, value); }
    }

    protected static PropertyInfo<string> ConcreteProp2Property =
      RegisterProperty<string>(c => c.ConcreteProp2);
    public string ConcreteProp2
    {
      get { return GetProperty(ConcreteProp2Property); }
      set { SetProperty(ConcreteProp2Property, value); }
    }
  }
}

And then I noticed something odd: according to the compiler, ConcreteProp1 and ConcreteProp2 were not defined. Even worse is the situation when you choose to upgrade your properties not using lambda expressions, but PropertyInfo objects, like this:

    protected static PropertyInfo<string> ConcreteProp3Property =
      new PropertyInfo<string>("ConcreteProp3Property");
    public string ConcreteProp3
    {
        get { return GetProperty(ConcreteProp3Property); }
        set { SetProperty(ConcreteProp3Property, value); }
    }
because this will compile - and run. Until you create a second child class MyConcreteClass2, instantiate it, then instantiate a MyConcreteClass1 – and then you will get a cryptical runtime error message saying “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated”.

Fortunately the CSLA framework comes with sources, and after some rooting around I found the culprit, if you can call it that, in Csla.BusinessBase:

protected static PropertyInfo<P> 
  RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
{
  PropertyInfo reflectedPropertyInfo = 
    Reflect<T>.GetProperty(propertyLambdaExpression);

  return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(
    typeof(T), reflectedPropertyInfo.Name));
}

Although MyConcreteClass1 inherits from MyBaseClass, MyBaseClass inherits in turn from templated class BusinessBase<MyBaseClass>. Therefore, in RegisterProperty called from MyConcreteClass1 T is still MyBaseClass. It does not matter that I actually called it from a child class. So what happens is that all the statics are defined in the base class MyBaseClass. If you are using the lambda variant to register, the compiler saves your *ss, but if you use the PropertyInfo method something weird happens. Remember, statics in a class are initialized as soon as you touch any one of statics. So what happens is: you instantiate your concrete child class, immediately the statics of both the concrete and the base class are initialized, and all the properties are registered in the base class. If you try to instantiate a second concrete child class, Csla finds that your base class properties are already initialized, and the dreaded “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated” error message appears.

Now you can of course change the way you implement classes. I might make MyBaseClass generic as well, then T changes along. But when upgrading an existing API out of a situation in which direct inheritance used to be perfectly legal, it’s a different story.

There are actually two ways out of this. The first one is: use PropertyInfo, but explicitly name the object type to which the property belongs

protected static PropertyInfo<string> ConcreteProp3Property =
  RegisterProperty(typeof(MyConcreteClass1), 
  new PropertyInfo<string>("ConcreteProp3Property"));
public string ConcreteProp3
{
    get { return GetProperty(ConcreteProp3Property); }
    set { SetProperty(ConcreteProp3Property, value); }
}

This works, but I like the solution below better, because that uses lambda expressions again and so your friend the compiler ;-) can help you catch typo’s. The only way I see to realize that is to add a static method at the bottom of your class

private static PropertyInfo<T> RegisterPropertyLocal<T>(
  Expression<Func<MyConcreteClass1, object>> propertyLambdaExpression)
{
  var reflectedPropertyInfo = 
  Reflect<MyConcreteClass1>.GetProperty(propertyLambdaExpression);
  return RegisterProperty(typeof(MyConcreteClass1),
    Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<T>(
    typeof(MyConcreteClass1),
    reflectedPropertyInfo.Name);
}
and then register your properties like this from now on:
protected static PropertyInfo<string> ConcreteProp1Property = 
  RegisterPropertyLocal<string>(c => c.ConcreteProp1);
public string ConcreteProp1
{
  get { return GetProperty(ConcreteProp1Property); }
  set { SetProperty(ConcreteProp1Property, value); }
}

The drawback of this solution is, of course, that you have to define a static RegisterPropertyLocal in every inherited class you define. But at least you will be saved from typos and weird runtime errors.

Now you are ready to upgrade, but I would recommend recording some macros to do the actual syntax change, unless you are very fond of very dull repetitive typing jobs ;-)

01 April 2010

Caveats when migrating existing CLSA.NET objects to Silverlight

So you have been working for a while with CSLA .NET by Rockford Lhotka and now you want – like me – jump on the Silverlight bandwagon. So you want to reuse the business objects in Silverlight. There are some nice samples in the cslalight samples but when I started to try to use my own business objects, things did not run so smoothly as the samples suggest.

The samples by Rockford show the general outline:

  • You make a second assembly into which you add the exisiting business class source files as a link
  • You start adding specific Silverlight functionality surrounded by
    #if SILVERLIGHT (…) #endif preprocessor directives
  • You make sure that the server stuff like data access is not active in the Silverlight configuration (#if !SILVERLIGHT)
  • You add a Silverlight-specific factory method to load an object, that looks a bit like this:
public static void Get(int id, 
  EventHandler<DataPortalResult<MyBusinessClass>> callback)
{
  var dp = new DataPortal<MyBusinessClass>( );
  dp.FetchCompleted += callback;
  dp.BeginFetch( new IdCriteria(id) );
}

If you try to call this from your Silverlight client the result is - unless you are very lucky - most likely that the sky starts caving in. Turns out there are a few 'hidden requirements' –or at least some less apparent ones. Maybe there are more, but this was what I found so far:

  • Both the Silverlight and the full framework assemblies must have the same name, so even if your projects are called MyLib.Server and MyLib.Client, the resulting dll’s must have the same name, for example MyLib.dll.
  • If your full framework assembly is signed, your Silverlight assembly should be signed as well. They then also must have the same version number – all the way to the build number. This is important – and it took me the most time before the penny dropped.
  • All the Silverlight classes must have public constructors. So you add
#if! SILVERLIGHT   
  private MyBusinessClass()
  {
  }
#else
  public MyBusinessClass()
  {
  }
#endif
  • Properties should be defined in the ‘modern’ format. You have still properties in this format?
private string _oldProp = string.Empty;

public string OldProp
{
  get
  {
    return _oldProp;
  }	 
  set
  {
    if (value == null) value = string.Empty;
    if (!_oldProp.Equals(value))
    {
      _oldProp = value;
      PropertyHasChanged("OldProp");
    }
  }
}
Tough luck. Change that into the 'new' form, e.g.
private static PropertyInfo NewPropProperty = 
  RegisterProperty(c => c.NewProp);
public string NewProp
{
	get { return GetProperty(NewPropProperty); }
	set { SetProperty(NewPropProperty, value); }
}
  • Criteria objects should have public constructors as well, and should be public classes – that is, if you have defined them as private classes inside your business object, you should make them public
  • Your Criteria should implement IMobileObject. The easiest way is to let your class descend from CriteriaBase, but then you will find out that although the class is serialized to the server, the properties are not. Turns out that for Criteria objects the property format has changed too. In the past you could just make a simple class with a few getters and setters, now you have to make something along this line:
[Serializable]
public class IdCriteria : CriteriaBase
{
  public static PropertyInfo<int> IdProperty = 
    RegisterProperty(typeof(IdCriteria), new PropertyInfo<int>("Id"));
  public int Id
  {
    get { return ReadProperty(IdProperty); }
    set { LoadProperty(IdProperty, value); }
  }
  public IdCriteria() { }

  public IdCriteria(int id)
  {
    Id = id;
  }
}

So, although CLSA ‘light’ promises a lot of reuse (which is true of course, in the case of business and validation rules) you need a lot of extra plumbing to get going. And mind you, this is a simple single object that I only read – I haven’t covered lists yet, nor updates and deletes. The power of CSLA can come to Silverlight – but certainly for existing libraries it is not quite a free ride. But then again - this is Silverlight, so it should run on Windows Phone 7 series as wel... which will be my next experiment. I will keep you posted!

01 March 2010

Running CSLALight 3.8.2 under .NET 4 and Silverlight 4

Update December 23, 2013: this is article is pretty much outdated. Currently it gets a lot of traffic. I hope some people reading it would like to leave a comment and tell me WHY the are reading it

CSLA .NET by Rockford Lhotka is a business layer framework, but it does not run under .NET4 and Silverlight 4 yet. Fortunately this framework comes with sources, and I set out to get a simple sample application to run under Silverlight 4. As always, it is a lot more work to find out what to do than to actually do it, but eventually I was successful. To make life for those who want to follow me a little harder: I am using Visual Studio 2010RC and the Silverlight 4 tools beta. I know those are not supposed to work together, but if you follow this procedure you actually can run Silverlight 4 tools inside the RC. This procedure, however, included hacking an installer and then editing some registry keys. Follow this procedure at your own risk. It worked for me, but maybe the procedure for getting CSLA to run under .NET 4 and Silverlight 4 may work under VS2010 B2 as well.

1. Download these files
  • cslalightcs-3.8.2-100201.zip
  • lightsamples-3.8.2-100201.zip

Which can all be found on the CSLA.NET site.

2. Unzip the files in working directories

The net result should be something like this
CSLA
  - clsacs
  - clsalightcs
  - Dependencies
  - README.txt
LightSamples
  - cslalight
  - readme.txt

3. Compile clsacs.sln for .NET 4.0
  • Start Visual Studio 2010, and open the solution clsacs.sln in CSLA\cslacs.
  • Let Visual Studio 2010 convert the project
  • right-click the csla project, select properties and change the target framework to .NET 4.0
  • Change the active solution configuration to “Release”
  • Rebuild the solution. This will give some errors. If you check the clsa project’s references, you will see warning signs indicating missing assemblies, which are:
    • PresentationCore
    • PresentationFramework
    • System.Printing
    • System.Runtime.Serialization
    • System.ServiceModel
    • System.Workflow.Runtime
    • WindowsBase
  • Remove these references and replace them by their .NET 4.0 brethren.
  • Add a reference to System.Xaml
  • Rebuild the solution. You will get a whole lot of warnings but CSLA will compile.
4. Compile cslalightcs.sln for Silverlight 4
  • Start Visual Studio 2010, and open the solution clsalightcs.sln in CSLA\cslalightcs.
  • Let VS2010 convert the project
  • right-click the Cslalight project, select properties and change the Target Silverlight Version to 4.0
  • Add a reference to System.Net
  • Change the active solution configuration to “Release”
  • Rebuild the solution. Once again, a whole lot of warnings but CSLAlight will compile

5. Convert and compile the SimpleApp sample

If you browse into LightSamples\cslalight\cs\SimpleApp with the Windows Explorer you will find a simple CSLA/CSLA light solution that demonstrates the basic setup of the CSLA data portal for Silverlight. We will convert this application to work under our freshly created CSLA and CSLALight libraries.

  • Open the SampleApp.sln solution with Visual Studio 2010
  • Let Visual Studio 2010 convert the solution
  • Click “Yes” to upgrade to .NET 4.0 and ignore further errors
  • The solution contains 4 projects.
    • Set the Target Silverlight Version of Library.Client and SimpleApp to Silverlight 4
    • Set the target framework for Library.Server to .NET 4.0. No need to change SimpleApp.Web, Visual Studio has already done that
  • In project Library.Client:
    • Check the references. You will find “Csla” missing.
    • Remove the reference
    • Click Add Reference/Browse
    • Browse to CSLA\cslalightcs\Csla\ClientBin.
    • Add References to Csla.dll and System.Windows.Interactivity.dll
  • Repeat the procedure for SimpleApp
  • In project Library.Server:
    • Check the references. You will find “Csla” missing.
    • Remove the reference
    • Click Add Reference/Browse
    • Browse to CSLA\cslacs\Csla\bin\Release
    • Add a Reference to Csla.dll
  • Repeat the procedure for SimpleApp.Web.

6. Change the ServiceReferences.ClientConfig

This actually took me the longest, because I did not understand the problem. If you run the application (right click SimpleApp.Web/SimpleAppTestPage.aspx and click “View in Browser”), enter some values “for “Name” and “City” and hit “Save” you get an error indicating that there is no endpoint for contract “WcfPortal.IWcfPortal”.

Apparently something has changed in how Service Contracts are referenced in Silverlight 4. The solution turns out to be this:

  • open the ServiceReferences.ClientConfig file in the SimpleApp project
  • Locate the text contract="Csla.WcfPortal.IWcfPortal" 
  • Remove the “Csla.” prefix, including the dot, so that only contract="WcfPortal.IWcfPortal" remains
  • Run SimpleApp.Web/SimpleAppTestPage.aspx again

Hit some values for “Name” and “City” again, hit “Save” and the text “Inserted Client” appears. You can set some breakpoints to see CSLA actually goes back to the server for that. And, of course, you can right-click on the Silverlight application, click “Silverlight” on the ‘context menu’ and see that actually runs under Silverlight 4

This of course guarantees by no means that all the features of Csla will work under Silverlight 4 but at least we can go forward playing around in this new environment.

16 December 2008

[Serializable] does not inherit (aka RTFM)

Of course, everybody knows that if you want to serialize an object, you need to decorate the class with the [Serializable] attribute. Right? Well, yes, and so do I, but I ran into a snag today: it is an attribute, not a property so it does not inherit. If you consider the following code
using System;

namespace demo
{
    [Serializable]
    public class BaseClass
    {
        public string AProperty { get; set; }
    }

    public class ChildClass : BaseClass
    {
        public string AnotherProperty { get; set; }
    }
}
you will find that Childclass will not serialize with BinaryFormatter, although its base class will. This is of course quite evident, but a more interesting gotcha occurs when you add a third class:
    [Serializable]
    public class ChildClass2 : ChildClass
    {
        public string FinalProperty { get; set; }
    }
This won't serialize either, because halfway up it's class hierarchy there's a non-serializable class. In plain vanilla .NET this will generate an "Failed to serialize. Reason: Type 'demo.ChildClass' in Assembly 'bla bla bla' is not marked as serializable", precisely pinpointing the problem. If it happens (as in my case) deep down inside a CSLA dataportal, all you get is an error message like
System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.
And you might spend quite some time finding out it is caused by a non-serializable class somewhere in your class hierarchy. So, check your attributes, folkes ;-) Or run FxCop (and read the warnings)