CslaDataProvider and Callback method

CslaDataProvider and Callback method

Old forum URL: forums.lhotka.net/forums/t/9215.aspx


arobadol posted on Thursday, July 15, 2010

Dear all,

 

I've just read the article here which introduce CSLA and Silverligth. I may have miss something in article but there some static factory created for the business entity "GetCompany" This method takes as parameter the Company criteria and a call back method. On the last page Rockford introduce the CSLADataProvider and make use of the static factory method. But I cannot understand how the callback parameter is provided to the static factory...

 

Any help would be appreciated.

 

Regards,

RockfordLhotka replied on Thursday, July 15, 2010

CslaDataProvider invokes static factory methods only if they have the correct method signature. In Silverlight this means the method must accept the callback parameter.

CslaDataProvider actually handles the callback itself, and uses the callback to know that it needs to update its Data and ObjectInstance properties with the results. It then raises appropriate data binding events (PropertyChanged) so Silverlight knows to refresh the UI.

As a UI developer, when you use CslaDataProvider you typically write little or no C#/VB code - the work is handled through XAML and CslaDataProvider.

However, you should also know that Microsoft is clearly not continuing down the data provider path. In Visual Studio 2010 and Blend 4 they've moved away from using any data provider objects.

So while CSLA 4 still has the CslaDataProvider, it is my recommendation that people explore alternatives - most notably the MVVM design pattern. CSLA 4 (and 3.8) provides support for MVVM that is quite comparable to the data provider model, but I think is actually better.

arobadol replied on Saturday, July 17, 2010

Thanks Rocky for the answer.

I cannot agree more to your point . I'm clearly taking that direction to. I'm trying to find a nice way to plug the Factory operations to my UI. I'm currently prototyping an application which will be build on top of Caliburn and CSLA 4.0.

In Caliburn there is a concept of WebServiceResult which is used to connect a UI operation and a web service call. I was trying to do the same thing and building a sort of CSLAFactoryResult.

 

This class will Implement the IResult interface (Caliburn) and will take as parameter the Factory operation and the callback... My problem is that we are using Factory Operation which are static operation that takes the call back as parameter:

FactoryOperation(DataPortalResult<BusineeObject callback>)

While the WebServiceResult is build on top of a Service reference proxy which is build on top of an async operation and a compelted event.

Operation()

OperationCompleted+= eventHandler

I need a way to kind of encapsulate my callback with ui operation (Stop the busy animation...) but it is hard as this is passed directly to the factory.

 

I have started by looking at the CSLADataProvider source code to inspire my self on this one to build my CSLAFactoryResult :)

I do not know If I have make my self clear but if so I will be more than happy to get some advice on this. If not I can try to provide more information on this :)

Thansk for your help.

arobadol

Alexandre

 

 

arobadol replied on Saturday, July 17, 2010

I found what I wanted to do :)

Maybe this short peice of code will help someone else :)

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Reflection;

using Caliburn.Core;

using Caliburn.PresentationFramework;

using Csla;

using Csla.Properties;

using Csla.Reflection;

using Microsoft.Practices.ServiceLocation;

 

namespace Kpm.Finance.Client.Infrastructure

{

    /// <summary>

    /// This class handle the Factory method call and the callback operation

    /// </summary>

    /// <typeparam name="TCslaBusinessEntity">the CSLA Type the factory method is for</typeparam>

    public class CslaFactoryResult<TCslaBusinessEntity> : IResult

    {

        private string _factoryMethod;

        private readonly IList<object> _factoryParameters;

        private readonly EventHandler<DataPortalResult<TCslaBusinessEntity>> _callback;

 

        /// <summary>

        /// Constructor

        /// </summary>

        public CslaFactoryResult(string factoryMethod, IList<object> factoryParameters) : this(factoryMethod, factoryParameters, null) { }

 

        /// <summary>

        /// Constructor

        /// </summary>

        public CslaFactoryResult(string factoryMethod, EventHandler<DataPortalResult<TCslaBusinessEntity>> callback) : this(factoryMethod, new List<object>(), callback) { }

 

        /// <summary>

        /// Constructor

        /// </summary>

        public CslaFactoryResult(string factoryMethod, IList<object> factoryParameters, EventHandler<DataPortalResult<TCslaBusinessEntity>> callback)

        {

            _factoryMethod = factoryMethod;

            _callback = callback;

            _factoryParameters = factoryParameters;

        }

 

 

        public void CallOriginalCallBack(object sender, DataPortalResult<TCslaBusinessEntity> arg)

        {

            ServiceLocator.Current.GetInstance<ILoadScreen>().StopLoading();

            //or re-enable the control that caused the service to be called:

            //ChangeAvailability(message, true);

 

            if (_callback != null)

                _callback(sender, arg);

 

            Completed(this, null);

 

        }

 

        #region Implementation of IResult

 

        public void Execute(IRoutedMessageWithOutcome message, IInteractionNode handlingNode)

        {

            ServiceLocator.Current.GetInstance<ILoadScreen>().StartLoading();

            //if you would rather disable the control that caused the service to be called, you could do this:

            //ChangeAvailability(message, false);

 

            //If a call back was provided we assume the factory method will expect one

            if (_callback != null)

                _factoryParameters.Add(new EventHandler<DataPortalResult<TCslaBusinessEntity>>(this.CallOriginalCallBack));

            object[] parameters = _factoryParameters.ToArray();

            object result = null;

            Exception exceptionResult = null;

 

            try

            {

                // get factory method info

                BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;

                System.Reflection.MethodInfo factory = typeof(TCslaBusinessEntity).GetMethod(_factoryMethod, flags, null, MethodCaller.GetParameterTypes(parameters), null);

                if (factory == null)

                {

                    // strongly typed factory couldn't be found so find one with the correct number of parameters 

                    int parameterCount = parameters.Length;

                    System.Reflection.MethodInfo[] methods = typeof(TCslaBusinessEntity).GetMethods(flags);

                    foreach (System.Reflection.MethodInfo method in methods)

                        if (method.Name == _factoryMethod && method.GetParameters().Length == parameterCount)

                        {

                            factory = method;

                            break;

                        }

                }

                // If no matching factory could be found, throw exception

                if (factory == null)

                    throw new InvalidOperationException(string.Format(Resources.NoSuchFactoryMethod, _factoryMethod));

 

                // invoke factory method)

                try

                {

                    result = factory.Invoke(null, parameters);

                }

                catch (DataPortalException ex)

                {

                    exceptionResult = ex.BusinessException;

                }

                catch (TargetInvocationException ex)

                {

                    if (ex.InnerException != null)

                    {

                        exceptionResult = ex.InnerException;

                        var dpe = exceptionResult as DataPortalException;

                        if (dpe != null && dpe.BusinessException != null)

                            exceptionResult = dpe.BusinessException;

                    }

                    else

                        exceptionResult = ex;

                }

                catch (Exception ex)

                {

                    exceptionResult = ex;

                }

 

            }

            catch (Exception ex)

            {

                exceptionResult = ex;

            }

 

 

 

 

        }

 

        public event Action<IResult, Exception> Completed = delegate { };

 

        #endregion

 

        private void ChangeAvailability(IRoutedMessage message, bool isAvailable)

        {

            (from trigger in message.Source.Triggers

             where trigger.Message == message

             select trigger).Apply(x => x.UpdateAvailabilty(isAvailable));

        }

    }

}

Copyright (c) Marimer LLC