Category: CSLA

My 2 cents on new CSLA

Injecting NHibernate Repository into CSLA ObjectFactory is much easier than doing this in CSLA BO.

AutoMapper is very hard to use to pass data from NHibernate model to CSLA BO due to many flag setting in DataPortal methods.

Aggregate root pattern is missing from CSLA, processing child list is completely different in ORM world. CSLA is still following the table-BO one-to-one style.

CSLA sample app has demo code of using ORM like EF or Linq2Sql, but MODEL in those ORM is just used as data structure. It’s fair to keep CSLA BO business rich, but why use ORM for? Just to connect to database?

The way CSLA using WCF is weird, a real world SOA app should not have a contract with just CRUD operation defined in it.

Exception handling is different, while it definitely makes sense for UI/F5 developers, it drove my nuts when looking for exception when things don’t work, exception suppose to bubble up all the way, not hidden in control somewhere.

N-level undo is interesting. Again, who is using it?

Most wonderful features in CSLA:

  • Very rich and thoughtful UI controls, like cslaActionExtender, error provider and the usage of datasource on WinForms/WPF. Drag and drop, property setting, etc… I really miss it, especially when doing UI tasks.
  • Broad UI/OS support, even covers iOS with monoTouch on hand. Using it as a rich screen DTO in app isn’t a bad idea. For data access, stick with NHibernate.

My demo app of how to use CSLA with NHbernate. Value Object pattern is used to process child line item list, flag comparison when updating list is possible, but not worth if lint_item_id doesn’t matter.

IRepository

I was trying to write a similar post as Mike did. Because I’m currently using LINQ DynamicQuery, so my IRepository looks like this:


    public interface IDynamicQueryable<T> 
    {
        IEnumerable<T> FindAllByCriteria(string criteria);
        IEnumerable<T> FindAllByCriteria(Func<T, bool> criteria);
    }

    // Most simple repository implement this one. 
    public interface IRepository<T>  
    {         
              T FindById(int id);
              T Insert(T data);
              T Update(T newData, T oldData);
              void Delete(T data);
     }

    // Some fancy entities implement this one instead. 
    public interface IDynamicQueryableRepository<T> : IDynamicQueryable<T>, IRepository<T>{}

I spilt the dynamic part from IRepository, just trying not annoy developer create too many never used FindAll() method in their entities. And also I think this is closer to Interface segregation Principle (not really sure). But this indeed gave me flexibility to control the function diversity on different entities, e.g., some entities might never need list-editing/retrieval function.

I do like this LinqDynamicQuery very much and don’t mind to make my repository coupled to Func<T, bool> (what’s this indeed? And what’ the difference than Expression<Func<T, bool>> shown in Fluent NHibernate’s IRepository?)  Here is a good example, if no DynamicQuery:


    public interface ICityRepository : IDynamicQueryableRepository<CityBO>
    {
        IEnumerable<CityBO> FindAllByProvinceId(int provinceId);
        IEnumerable<CityBO> FindAllByCountryId(int countryId);
    }

By using DynamicQuery,


    public class CityListFactory : BusinessListBaseServerFactory<CityBOCollection, CityBO, ICityRepository>, ICityListFactory
    {
        public CityBOCollection Fetch(CountryBO parent)
        {
            // Don't need FindAllByCountryId() any more.
            return Fetch(x => x.CountryId == parent.CountryId);
        }
        public CityBOCollection Fetch(ProvinceBO parent)
        {
            return Fetch(x => x.ProvinceId == parent.ProvinceId);
        }
    }

Extract Validation rules out from CSLA BO

The first priciple of SOLID rules is SRP, it would be nice if we can extract validataion rules out from BO. And I couldn’t belive it was so easy to do implement.

The classic way:

private void AddCustomRules()
        {
            // Custom validation
            ValidationRules.AddRule<EmailBO>(EmailRoleValidValues<EmailBO>, EmailRoleProperty, 1);

        }

The revised version:

// EmailBO
   protected override void AddBusinessRules()
   {
      EmailRuleFactory.CreateOn(ValidationRules);
   }

public class EmailRuleFactory
{
   public static void CreateOn(ValidationRules rules)
   {
      rules.AddRule<EmailBO>(EmailRoleValidValues<EmailBO>, "EmailRole", 1);
   }

   private static bool EmailRoleValidValues<T>(T target, Csla.Validation.RuleArgs e) where T : EmailBO
   {...}
 

All the validation tests still passed!

Note: I had to expose protect Parent field from BusinessBase. And PropertyInfo is not available either, fortunately ValidationRules.AddRule() can still take string literal.

This might also be helpful is user wants to switch between different sets of valudation rule based on certain instance value.

We could do the same thing to AuthorizationRules which will be more meaningful. Security should definitely be built as a separated common service, instead of building into Domain Object.

Enable DataGrid Header-Clicking Sorting

Most search results  said the header-clicking-sorting feature comes internally with dotNet Framework. But for some reason I just could make this happen, until I read an old article on MSDN about custom data binding, which kept mentioning about Rocky. And the reason is very simple, programmer should bind a SortableBindingList<T> to dataGrid to make use of those internal sorting features.

Csla.EditableRootList has to be wrapped in Csla.SortedBindingList then to bind to dataGrid.

SortedBindingList has most of the functions embeded including: Add, Insert, Delete, but not Save. I need to convert SortedBingList back to EditableRootList by using it’s internal property: SourceList.

Rocky didn’t make SortedBindingList serializable for some reason. Anyway, the UI code is very simple:


        public CountryBOCollection List
        {
            get
            {
                return (CountryBOCollection)
                  ((SortedBindingList)this.countryBOCollectionBindingSource.DataSource)
                      .SourceList;
            }
            set
            {
                this.countryBOCollectionBindingSource.DataSource
                    = new Csla.SortedBindingList(value);
            }
        }

I tried to move this type conversion to presenter, then I realized I need two lists in presenter: one sortable list for displaying and editing, one savable list just for saving. Presenter code is polluted just by this limitation in SortedBindingList. It looks much better by leaving type conversion still in UI, and who knows someday this limitation might go away?

Csla.ObjectFactory III – What’s wrong with UpdateChildren()

Derick Bailey’s post about Csla vs DDD brought out a simple but very interesting question :

Which one is correct?
Person.AddCertificate(), or Person.Certificates.Add()?

Almost the same? But it turns out the 2nd one is NOT “correct”, at least, not in DDD way.

That’s the problem in CSLA. Always thinking in table, data-centric design/dev. An extreme example, FieldManager.UpdateChildren().

How about save? Person.UpdateEmail() or Person.Email.Update(). [Email.Child_Update() in classic CSLA way.]

CSLA is not an ORM tool/framework, but BO carries all the dirty flags, in fact it’s DataPortal doing all the relationship maintenance work. RootBO.Save() is handling all the updates of its children, through FieldManager.UpdateChildren() jumping into each childBO’s internal private Child_XYZ methods. Handy, “clean”, but it’s not “correct”.This is the exactly same problem when I was trying to switch to the new Csla.ObjectFactory way: I had to keep an extra set of Protal methods in child BO, those child portal method,  to work with Parent BO’s FieldManager.UpdateChildren() method.

What if we ignore FieldManager completely? Just let Person.Save() directly call DataPortal.Update<EmailBO>(person.Email) ? Or DataPortal.Update<TelephoneBOCollection>(person.Telephones) ? Then child BO can still use  the general AbstractFactory which only have root level CRUD methods.

The direction Rocky made in ObjectFactory looks right, child CRUD should be done by root BO.  The thing is, it’s not backwards completable. It’s trying to retire FieldManager.UpdateChildren()!

The update route should be RootBO.Save -> Root Factory.Update -> Child Factory.Update, don’t call child BO’s internal Child_XYZ anymore.

Currently for legacy reason I still keep the following code in my ChildBO to bump calls from parent to child’s own factory, those UpdateChildren() in root BO can be alive for awhile, until I move them to root factory, which should be the newly strongly-typed customized UpdateChildren().


private void Child_DeleteSelf(){ DataPortal.Delete(this);}

private void Child_Insert(IParent parent){
     this.ParentId = parent.Id;
     DataPortal.Update(this);
}

private void Child_Update(){
     var newBO = DataPortal.Update(this);
     DataMapper.Map(newBO, this);
}

It might just looks like a wrapper trick, but those DataPortal calls are actually in Factory class now which indeed is in an external true service layer.

In my app, it’s one AbstractFactory for all BOs, both root and child.

I do have a problem now, where should I put transaction scope attribute? It shouldn’t be a big deal, possible solutions:

  1. Create some extra methods in factory not in transaction Scope dedicated for child methods,
  2. Unit of Work pattern?

Look back Ryan’s ProjectTrackerHybrid code, all the child propertis are not registered! Which means they are not in fieldmanager at all. It’s ORM’s job to handle the realationship UpSet (Update/Insert).

Csla.ObjectFactory Part II – Difficulties on Child BO

I was wondering  why CslaFactory only needs to implement CRUD, no child methods at all. Other developers post the  same question on forum.

Rocky’s answer made sense, it your own Facotory’s responsibility to handle all those relationship. My specific problem on this is, FiledManager.UpdateChildren() is not available any more.

First, the FieldManager property in BO is protected, this can be fixed by adding new method in our BaseBO to make it public. The root BO changed to CslaFactory then. But, next challenge is, this UpdateChild is not going through DataPortalSelector->DataPortal_XYZ route, it still uses Reflection to look up the ‘Child_XYZ” method right in your child BO, not in CslaFactory class at all!

You have to manage your own update route by looping through all the children from your root BO! Forget the powerful FieldManager.UpdateChildren().

Relationship is built in DAL. ?? When start using DTO, I know it is the dead weakness. The word around is pulling relationship up to Csla BO and rely on those magic UpdateChildren methods. Now, updateChildren is gone, I have to create a real business explicit UpdateChildren.

    public class AbstractObjectFactory : ObjectFactory, IBusinessBaseServerFactory
        where BO : MyBusinessBase
        where TRepository : IRepository
        where DTO : class, new()
    {
        protected IRepository _repository = StructureMap.ObjectFactory.GetInstance();

        public virtual BO NewBO()
        {
            return (BO)Activator.CreateInstance(typeof(BO), true);
            //            return new BO();
        }

        public virtual void InsertChildren(BO bo){}
        public virtual void UpdateChildren(BO bo){}
        public virtual void DeleteChildren(BO bo){}

        public virtual BO Create()
        {
            var obj = NewBO();
            MarkNew(obj);
            obj.GetValidationRules().CheckRules();
            return obj;
        }

        public virtual BO Insert(BO bo)
        {
            var data = _repository.Insert(bo.BuildDTO());
            if (data == null) throw new DataException(“Repository Insert return null.”);
            bo.LoadFromDTO(data);

            InsertChildren(bo);
            // FieldManagar().UpdateChildren(bo) is not through CslaFactory.
//            bo.GetFieldManagar().UpdateChildren(bo);

            return bo;
        }

    public class StakeholderFactory : AbstractObjectFactory
        , IStakeholderFactory
    {
        public override void InsertChildren(StakeholderBO bo)
        {
            // Update Alias Name Child
            var factory = new StakeholderAliasNameFactory();
            for (int i = 0; i < bo.AliasNames.Count; i++)             {                 bo.AliasNames[i] = factory.Insert(bo.AliasNames[i]);             }         } [/sourcecode] This looks weird. And my solution of mocking Parent for testing update Child is useless then, because that assume root BO is calling FiledManager.UpdateChildren. One solution is to  re-write those update children code into my CslaFactory class. More coding, does it look more clear? I’m not sure. One of my root BO has 7+ children, I don’t think it’s worth to move.

Another quick dirty fix might be, still leave those Child_XYZ methods in Child BO for legacy purpose, inside put DataPortal_XYZ to redirect call to CslaFactory. This solution can keep parent update code same as before, still using UpdateChildren(), also the Child BO will look more like a switchable BO.

Enough, now I fully understand Ryan’s statement: Csla is great, but we need relationship.

Look how Ruby and NH dealing with relationship: has_many, belongs_to. Simple and clear.

Csla.ObjectFactory

This is  a new feature from Csla 3.6, which is trying to make Csla more TDD friendly.

Benefits:

DataPortal_XYZ methods can be moved into your own ObjectFactory class, BO will look a little bit thinner. Yes, you can now make BO contructor to be public, ( in standard csla way BO’s ctor should be private), if you are tired of using Activator.CreateInstance.

Because now you have full control to this ObjectFactory, and this class is not static, you can mock it when unit-testing UI/Presenter. But, the default usage of ObjectFactory doesn’t support Interface. Fortunately,  Rocky allow you to create your own FactoryLoader, by setting it into your app.conifg to redirect:

<appSettings>
<add key=”CslaObjectFactoryLoader” value=”YourNameSpace.YourFactoryLoader, YourAssembly” />

Ryan Kelley is using this tech to create his GenericFactoryLoader in his ProjectTrackerHybrid demo.

We have lots of Stored Procedures to deal with, so create a base AbstactObjectFactory is very hard. So I changed Ryan’s GenericFactoryLoader to make it not taking generic interface.

Here is what I tried:


        public virtual Type GetFactoryType(string factoryConnectionString)
        {
            if (factoryConnectionString == null)
                throw new ArgumentNullException("factoryConnectionString");

            parser.Parse(factoryConnectionString);

            var factoryTypeName = parser.FactoryType;

            // parser doesn't work , use csla default ObjectFactoryLoader
            if (string.IsNullOrEmpty(factoryTypeName))
                return new ObjectFactoryLoader().GetFactoryType(factoryConnectionString);

            return Type.GetType(factoryTypeName);
        }

        public virtual object GetFactory(string factoryName)
        {
            var factoryType = GetFactoryType(factoryName);
            if (factoryType.IsInterface)
                return StructureMap.ObjectFactory.GetInstance(factoryType);

            return new ObjectFactoryLoader().GetFactory(factoryName);

        }

[CslaFactory("Factory Type=MyFactory.ICityFactory")]
// Classic way to declare ObjectFactory
//    [CslaFactory("MyFactory.CityFactory, MyFactory")]
[Serializable()]
public class CityBO :BusinessBase<CityBO>
{...}

Should always ignoreArgument when AssertWasCalled

I should have added this option in my test earlier, then I won’t waste 2+ hours today. The reason causing problem was very simple, AssertWasCalled() method in current verion RhinoMocks (3.5.0.1337 RC) doesn’t action consistently. I think it’s because comparing the object reference equalty. I had to add options=>options.IgnoreArguments() to get around from this.

Here is a piece of my MVP + CLSA test. Struggled for a while with Property setter, thanks God, it isn’t that hard.


    [TestFixture]
    public class When_initializing_view : EstablishContext
    {
        [Test]
        public void should_call_view_setter_if_id_exists()
        {
            // Arrange
            _mockOrganizationRepository.Expect(x => x.FindById(1)).Return(_stubOrganizationDTO);

            _mockView = MockRepository.GenerateMock<IEditDetailsView<OrganizationBO>>();

            _presenter = new EditDetailsPresenter<OrganizationBO>(_mockView);

            // Action
            _presenter.InitViewFor(1);

            // Assert
            _mockView.AssertWasCalled(x => x.CurrentBO = null,
                options =>options.IgnoreArguments() );
        }
    }

I then created a generic EditDetailsPresenter, worked as I expected with one concern left: How to mock DataPortal directly. Currently I am still mocking repository. Ideally I should mock DataPortal instead, otherwise I have to make sure there is at least one BO is fully functional.

Mocking DataPortal is very hard, because those Fecth, Create, Update and Delete are all static methods, I had to create an adapter to wrap those static methods, then using StructreMap again inside adapter enable switching between DataPortal and mock DomainDAO, here is what I have tried:

  1. Create DomainDAO and IDomainDAO,
    public class DomainDAO<BO> : IDomainDAO<BO>
    {
    public BO Fetch(object criteria)
    {
    return DataPortal.Fetch<BO>(criteria);
    }
    
    public BO Create()
    {
    return DataPortal.Create<BO>();
    }
    
    public BO Update(BO bo)
    {
    return DataPortal.Update<BO>(bo);
    }
    
    public void Delete(object criteria)
    {
    DataPortal.Delete<BO>(criteria);
    }
    }
    
    public interface IDomainDAO<T>
    {
    T Fetch(object criteria);
    T Create();
    T Update(T bo);
    void Delete(object criteria);
    }
    
    
  2. Create DAOManager to Get DomainDAO:
    public static class DAOManager
    {
    public static IDomainDAO<BO> DomainDAO<BO>()
    {
    return ObjectFactory.GetInstance<IDomainDAO<BO>>();
    }
    }
    
    
  3. Change classic factory method in BO from DataPortal to this new DAOManager.
    public static OrganizationBO GetOrganizationBO(int stakeholderId)
    {
    return DAOManager.DomainDAO<OrganizationBO>().Fetch(new SingleCriteria<OrganizationBO, int>(stakeholderId));
    //            return DataPortal.Fetch<OrganizationBO>(new SingleCriteria<OrganizationBO, int>(stakeholderId));
    }
    
  4. The presenter testing code can be changed to:
    
    [SetUp]
    public void SetUp()
    {
    _mockService = MockRepository.GenerateMock<IDomainDAO<OrganizationBO>>();
    ObjectFactory.Inject<IDomainDAO<OrganizationBO>>(_mockService);
    }
    
    [TearDown]
    public void TearDown()
    {
    ObjectFactory.ResetDefaults();
    }
    
    [TestFixture]
    public class When_initializing_view : EstablishContext
    {
            [Test]
            public void should_call_view_setter_if_id_exists()
            {
                // Arrange
                // We don't need to set return value here.
                _mockService.Expect(x => x.Fetch(new SingleCriteria<OrganizationBO, int>(68190)));
    
                _mockView = MockRepository.GenerateMock<IEditDetailsView<OrganizationBO>>();
    
                _presenter = new EditDetailsPresenter<OrganizationBO>(_mockView);
    
                // Action
                _presenter.InitViewFor(68190);
    
                // Assert
                _mockView.AssertWasCalled(x => x.CurrentBO = null,
                    options => options.IgnoreArguments() );
            }
    
            [Test]
            public void should_set_error_msg_in_view_if_id_not_exists()
            {
                // Arrange
                Exception ex = new Exception("Data Not Found", new DataNotFoundException());
                _mockService.Expect(x => x.Fetch(new SingleCriteria<OrganizationBO, int>(1)))
                    .IgnoreArguments()
                    .Throw(new DataPortalException("DataPortal.Fetch failed.",
                        ex,
                        null)); // See, we don't have to mock BO here, unless you try to read BO through exception in UI.
    
                _mockView = MockRepository.GenerateMock<IEditDetailsView<OrganizationBO>>();
    
                _presenter = new EditDetailsPresenter<OrganizationBO>(_mockView);
    
                // Action
                _presenter.InitViewFor(1);
    
                // Assert
                _mockView.AssertWasCalled(x => x.ShowError(null),
                    options => options.IgnoreArguments() );
            }
    

Fetch can be done this way, but I can’t mock Save() because it’s deep in Csla, unless I can override BusinessBase.Save() which is another mission impossible (too many internal classes involved). To make Csla TDD friendly, let ask for TypeMock to save us out.

 [TestFixture]
    public class When_view_firing_save_event : EstablishContext
    {
        [Test]
        public void should_set_success_msg_and_set_new_BO_in_view_if_save_new_bo_succeed()
        {
            // Arrange
            OrganizationBO orgBo = DataPortal.Create<OrganizationBO>();
            orgBo.Name = "test Org";
            Assert.That(orgBo.IsValid, orgBo.GetValidationMessage());

            _mockView = MockRepository.GenerateMock<IEditDetailsView<OrganizationBO>>();
            _mockView.Stub(x => x.CurrentBO).Return(orgBo).Repeat.Any();

            _presenter = new EditDetailsPresenter<OrganizationBO>(_mockView);

            // This won't work, because BusinessBase.Save() is tightly coupled to DataPortal.
            //_mockService.Expect(x => x.Update(orgBo)).IgnoreArguments();

            // Use TypeMock to mock DataPortal.Update() inside BusinessBase.Save()
            using (RecordExpectations recorder = RecorderManager.StartRecording())
            {
                  // CAUTION: ALL calls here are mocked!!!
                  recorder.DefaultBehavior.IgnoreArguments();
                  recorder.ExpectAndReturn(DataPortal.Update(orgBo), orgBo);
            }

            // Action
            _mockView.Raise(x => x.RequestSave += null, this, EventArgs.Empty);

            // Assert
            _mockView.AssertWasCalled(x => x.CurrentBO = null,
                                      options => options.IgnoreArguments());

            _mockView.AssertWasCalled(x => x.ShowMessage(null),
                                      options => options.IgnoreArguments());

    }

We can remove DomainDAO then if using TypeMock to mock DataPortal.

The new ObjectFactory in CSLA 3.6 seems can make this mock easier, looks like your own ObjectFactory is not static class anymore, different than DataPortal. By creating your own IDataPortal or IObjectFactory, as Ryan did,  mocking those service layer objects should become possible. Someday I will look into this CSLA.ObjectFactory thing if we aren’t going to TypeMock. Rocky’s statement indicates this will be a lot of work:

It is very important to realize that when using this factory model, the data portal does virtually nothing for you. It doesn’t automatically call MarkOld(), MarkNew() or MarkAsChild(). You assume total responsibility for creating and initializing the business object graph, and for setting the state of all objects in the graph.

But it seems Ryan’s ObjectFactroy sample code already finished most of them. One thing doesn’t fit our situation is, we need IRepository<> changed to IDomainObjectRepository in Factory.


        private readonly IRepository<T> _repository;
        public BusinessBaseServerFactory(IRepository<T> repository)
        {
            _repository = repository;
        }

So far, I think unless CSLA.ObjectFactory can provide an optional attribute something like “RepositoryType”, I have to create One ObjectFacotry per BO. Our libaray will become more messier.

Seperate concern between parent and child

Do we need to separate concern between parent object and its child? Say we have a stakeholder BO, which can have multiple email BOs, (an email BO collection). Then where should we place those specs/unit-tests for email BO?

Because emailBO is a child BO, the normal way to save it should be only through stakeholderBO.Save(). It’s possible that stakeholderBO might still be work-in-progress, or having problem caused by other childBO, e.g., telephoneBO. Or more likely, it’s not finish yet. Can we still work on EmailBO without worry too much about it’s parent – StakeholderBO?

So seperate concern is necessary. We need an interface to implement design-by-contract.

Create an IStakeholder interface, mock it in emailBO unit-test. (Thanks to Rhino, we don’t need worry about data portal any more. ) But we need to explicitly call SetParent() in emailBOCollection to simulate the LoadProperty behavior in stakeholderBO.

The test code:


            // Arrange
            var emailRepository = MockRepository.GenerateMock<IEmailRepository>();
            ObjectFactory.Inject<IEmailRepository>(emailRepository);

            EmailDTO OneValidTestDTO = new EmailDTO()
                                           {
                                               Address = "2@d.c", EmailRole = "Home",
                                               StakeholderId = 123, StakeholderEmailId = 456
                                           };

            emailRepository.Expect(x => x.Insert(null)).IgnoreArguments().Return(OneValidTestDTO);
            // or play the new inline constraints syntax
            emailRepository.Expect(x => x.Insert(Arg<EmailDTO>.Is.Anything)).Return(OneValidTestDTO); 

            IStakeholder mockStakeholderBO = MockRepository.GenerateMock<IStakeholder>();  

            // Action
            EmailBOCollection emails = EmailBOCollection.NewEmailBOCollection();

            // SetStakeholder is created in EmailBOCollection to call private SetParent through reflection.
            // This is optional because the second parm in DataPortal.UpdateChild() will be passed
            // to child_XYZ() as the parameter which is the real parent.
            // emails.SetStakeholder(mockStakeholderBO);   // IStakeholder should extend csla.IParent.

            var newEmail = emails.AddNew();
            // Make this new EmailBO valid.
            newEmail.Address = "1@dc.com";
            newEmail.EmailRole = "Home";

            Assert.That(emails[0].BrokenRulesCollection, Is.Empty, emails[0].BrokenRulesCollection.ToString());

            // this is to simulate the parent.Save() in the real world,
            DataPortal.UpdateChild(emails, mockStakeholderBO);
            // We don't want and can't call stakeholder.Save() here

            // Assert
            Assert.That(emails[0].StakeholderEmailId == OneValidTestDTO.StakeholderEmailId);
            Assert.That(emails[0].StakeholderId == OneValidTestDTO.StakeholderId);  

            // Reset to default
            ObjectFactory.ResetDefaults();

Unfortunately, SetParent(IParent) is a private method in IEditableObject and IEditableCollection. I had to create a public wrapper in my base class.


        public void SetStakeholder(IParent parent)
        {
            object[] parm = new object[] { parent };

            var method = this.GetType().GetMethod("Csla.Core.IEditableCollection.SetParent", BindingFlags.Instance | BindingFlags.NonPublic);

            method.Invoke(this, parm);
        }

But, later I figured out it’s not necessary, only if I am doing some parent-related validation in emailBO, say, an Organization type stakeholder can not have home email role.

Dataportal.Update() method is key to simulate parent.Save(), this old (3.0) syntax works great in my mock/TDD solution to CSLA.

Static field disappears on WCF

I spent 10+ hours on this problem, ‘Specified cast is not valid’ on a CSLA library deployed onto WCF host. I figured out this is caused by inherited properties in BO were lost. The propertyInfo list is different between server and client, one side (server) doesn’t contain those properties from baseBO.

More details, BO can be retrieved from WCF, change one of it’s property, save BO, then this problem occured. Debug turns out before saving, the client side still had a full list of properties including inherited ones, but after serilizing-deserilizing, the one transfered to server side magically lost those base properties should inherite from ancestor!

We know that by adding a dummy static field can fix the similar problem, but that only works in non-WCF mode. Why not in WCF mode? Somewhere CSLA and WCF/dotNet static fields doesn’t like each other, again.

I am tired of this kind of issues, fortunatelly, I found a work around.

Always keep a non-RunLocal DataPortal_Create method in BO, and create a NewYourBO() factory method calling this DataPortal_Create(). When you get this ‘Specified cast is not valid’ problem, just try to add this NewYourBO factory method right before your fetch operation. For a collectionBO, it should be in GetYourBOCollection()

internal static YourBOColleciton()
{
if (Csla.ApplicationContext.DataPortalProxy.Contains(“WcfProxy”)) YourBO.NewYourBO();
return DataPortal.FetchChild<YourBOCollection>();
}

For a non-collection BO, it should be in GetYourBO():

internal static GetYourBO()
{
if (Csla.ApplicationContext.DataPortalProxy.Contains(“WcfProxy”)) NewYourBO();
return DataPortal.FetchChild<YourBO>();
}

Looks like my extra code are doing a initialize work, setting up on both server and client side to make sure both side have the full property list ready.

Someday I will come back with a explaination.

Most of my problemic BOs are child type. I tried using DataPortal_CreateChild instead of DataPortal_Create, it failed. Perhaps the CreateChild one doesn’t return anything to client side.

There is a similar problem when moving multi-level inheritance to WCF host. The properties in middle level also be lost when fetching data down to client side. Similar workaround is to call the local constructor right before retrieve.

internal static GetYourBO()
{
if (Csla.ApplicationContext.DataPortalProxy.Contains(“WcfProxy”)) {
new YourBO(); // to trigger static field in local contrustctor
// Or Activator.CreateInstance(typeof(YourBO<T>), true);
NewYourBO(); // to trigger static field in remote constructor
}
return DataPortal.FetchChild<YourBO>();
}

Update:

Bought the newest eBook from Rocky, the solution is in OnDeserialized. We had to added base.OnDeserialized(context) because we are doing multi-level inheritance. Thanks Kevin, Thanks Rocky.

private static int _init; // This must be a private type, even protected type won’t work.
protected CommentBOBase()
{
_init = 0;
}

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
{
base.OnDeserialized(context);
_init = 0;
}

My experience is, we only need to add this piece of hacking code to those base classes with static fields declared. The inherited class doesn’t need to do this trick.

Related posts:

http://forums.lhotka.net/forums/thread/24472.aspx
http://forums.lhotka.net/forums/post/26822.aspx
http://forums.lhotka.net/forums/thread/26849.aspx