Converting 4.3 to 4.5 Object Factory Loader Never Called

Converting 4.3 to 4.5 Object Factory Loader Never Called

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


thaehn posted on Tuesday, July 23, 2013

About a year ago I tried to upgrade from 4.3 to 4.5 and gave up after noone on the forum could help.  I am trying it again.  I have run into the same problem again:  my Application Factory Loader is never called.  I cannot load my model into my view model because CSLA cannot find the assembly for the DAL.  I have the following in my web.config (I have a sample application structured after my production application):

  <appSettings>

    <add key="ObjectFactoryAssembly" value="Sample.Common.Library"/>

    <add key="CslaObjectFactoryLoader" value="Sample.Common.Library.Infrastructure.ApplicationFactoryLoader,Sample.Common.Library"/>

  </appSettings>

 

Puting breakpoint in my ApplicaitonFactoryLoader class reveal that the class is never called:

 

    /// <summary>

    /// Find the DAL for the Module and load it.

    /// </summary>

    public class ApplicationFactoryLoader : Csla.Server.IObjectFactoryLoader

    {

        /// <summary>

        /// The get factory type.

        /// </summary>

        /// <param name="factoryName">

        /// The factory name.

        /// </param>

        /// <returns>

        /// The <see cref="Type"/>.

        /// </returns>

        /// <exception cref="ArgumentException">

        /// Type not known.

        /// </exception>

        public Type GetFactoryType(string factoryName)

        {

            string assembly;

 

            if (factoryName.Contains("."))

            {

                assembly = string.Format("Sample.{0}.DAL", factoryName.Substring(0, factoryName.IndexOf(".")));

                factoryName = factoryName.Substring(factoryName.IndexOf(".") + 1);

            }

            else

            {

                assembly = "Sample.Common.DAL";

            }

 

            var typeName = string.Format("{0}.{1},{0}", assembly, factoryName);

            var factoryType = Type.GetType(typeName);

            if (factoryType == null)

            {

                throw new ArgumentException(string.Format("Cannot find type '{0}'", typeName));

            }

 

            return factoryType;

        }

 

        /// <summary>

        /// The get factory.

        /// </summary>

        /// <param name="factoryName">

        /// The factory name.

        /// </param>

        /// <returns>

        /// The <see cref="object"/>.

        /// </returns>

        public object GetFactory(string factoryName)

        {

            return Activator.CreateInstance(GetFactoryType(factoryName));

        }

    }

 

 

My ViewModel simply loads tries to load the model:

 

 

I have not made any changes to my ViewModelBase<T> which originated from CSLA's in 3.8 (I think) and merged with Caliburn Micro's.  Here is the Refresh implementation:

 

                /// <summary>

        /// Creates or retrieves a new instance of the Model by invoking a static factory method.

        /// </summary>

        /// <param name="factoryMethod">Static factory method action.</param>

        protected virtual void BeginRefresh(Action<EventHandler<DataPortalResult<T>>> factoryMethod)

        {

            try

            {

                Error = null;

                IsBusy = true;

 

                var handler = (EventHandler<DataPortalResult<T>>)CreateHandler(typeof(T));

                factoryMethod(handler);

            }

            catch (Exception ex)

            {

                Error = ex;

                IsBusy = false;

            }

        }

 

        /// <summary>

        /// Creates or retrieves a new instance of the

        /// Model by invoking a static factory method.

        /// </summary>

        /// <param name="factoryMethod">Name of the static factory method.</param>

        /// <param name="factoryParameters">Factory method parameters.</param>

        protected virtual void BeginRefresh(string factoryMethod, params object[] factoryParameters)

        {

            try

            {

                Error = null;

                IsBusy = true;

 

                var parameters = new List<object>(factoryParameters) { CreateHandler(typeof(T)) };

 

                MethodCaller.CallFactoryMethod(typeof(T), factoryMethod, parameters.ToArray());

            }

            catch (Exception ex)

            {

                Error = ex;

                IsBusy = false;

            }

        }

 

        /// <summary>

        /// Creates or retrieves a new instance of the

        /// Model by invoking a static factory method.

        /// </summary>

        /// <param name="factoryMethod">Name of the static factory method.</param>

        protected virtual void BeginRefresh(string factoryMethod)

        {

            BeginRefresh(factoryMethod, new object[] { });

        }

 

        /// <summary>

        /// The create handler.

        /// </summary>

        /// <param name="objectType">

        /// The object type.

        /// </param>

        /// <returns>

        /// The <see cref="Delegate"/>.

        /// </returns>

        private Delegate CreateHandler(Type objectType)

        {

            var args = typeof(DataPortalResult<>).MakeGenericType(objectType);

            System.Reflection.MethodInfo method = MethodCaller.GetNonPublicMethod(GetType(), "QueryCompleted");

            Delegate handler = Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(args), this, method);

            return handler;

        }

 

        private void QueryCompleted(object sender, EventArgs args)

        {

            try

            {

                var eventArgs = (IDataPortalResult)args;

                if (eventArgs.Error == null)

                {

                    var model = (T)eventArgs.Object;

                    OnRefreshing(model);

                    Model = model;

                }

                else

                {

                    Error = eventArgs.Error;

                    if (Debugger.IsAttached)

                    {

                        Debugger.Break();

                    }

                }

 

                OnRefreshed();

            }

            finally

            {

                UpdateStatus(string.Empty, false);

                IsBusy = false;

 

                if (Refreshed != null)

                {

                    // The refresh event needs to wait for the busy indicator animation to finish

                    // otherwise the focus is swallowed up by the busy indicator

                    DispatcherTimer timer = new DispatcherTimer();

                    timer.Interval = TimeSpan.FromMilliseconds(500);

                    timer.Tick += (s, e) =>

                        {

                            timer.Stop();

                            Refreshed(this, new EventArgs());

                        };

                    timer.Start();

                }

            }

        }

 

Any Ideas?  Everything works fine in 4.3...

Todd

 

        BeginRefresh(LoginRoot.GetLoginRoot);

thaehn replied on Tuesday, July 23, 2013

Somehow the view mode refresh code ended up at the bottom..sorry.  When I try to edit the original, everything gets doublespaced in the code.

Killian35 replied on Tuesday, July 23, 2013

There isn't quite enough context with your code. I'm assuming you're in Silverlight. How are you defining the ObjectFactory attributes on your business objects? Are you letting them be visible on the client side or hiding them through compiler directives?

thaehn replied on Wednesday, July 24, 2013

The only way I know how to assign it is through attributes:

    [Serializable]

    [Csla.Server.ObjectFactory("Shell.LoginRootDal")]

    public class LoginRoot : BusinessBase<LoginRoot>

I have a normal call to the data portal in my Business Object:

        #region Factory Methods

 

        /// <summary>

        /// The get login root.

        /// </summary>

        /// <param name="callback">

        /// The callback.

        /// </param>

        public static void GetLoginRoot(EventHandler<DataPortalResult<LoginRoot>> callback)

        {

            DataPortal.BeginFetch<LoginRoot>(callback);

        }

       

        #endregion

 

Todd

 

JonnyBee replied on Wednesday, July 24, 2013

Can you provide a sample solution for us that has the issue? 

thaehn replied on Wednesday, July 24, 2013

I sent the sample to your gmail account.

Todd

JonnyBee replied on Wednesday, July 24, 2013

Hi Todd, 

Easy solution - see your email. 

Basically - in CSLA 4.5 you must specify both DataPortalUrl and DataPortalProxy in order to use remote portal. 

Code from SimpleApp in the Silverlight Samples:

    private void Application_Startup(object sender, StartupEventArgs e)
    {
      //These 2 values must be set in order tu use remote wcfproxy 
      //Csla.ApplicationContext.DataPortalProxy = typeof(Csla.DataPortalClient.WcfProxy).AssemblyQualifiedName;
      //Csla.ApplicationContext.DataPortalUrlString = "http://localhost:1993/WcfPortal.svc";
 
      Csla.DataPortal.ProxyTypeName = "Local";
 
      this.RootVisual = new Page();
    }

And your code did not specify the DataPortalPRoxy so everything was running with Local proxy and then failed to
load classes that only exists on the .NET serverside.

Killian35 replied on Wednesday, July 24, 2013

Ok, if this is in Silverlight and the object factory is on the server, I had the same problem. If I wrapped the ObjectFactory  attribute in an #if !SILVERLIGHT compiler directive it would work fine. I didn't like having to do that, so I ended up having to assign an object factory loader to the FactoryDataPortal  in the App.xaml.cs class on the Silverlight side:

FactoryDataPortal.FactoryLoader = new NullFactoryLoader();

The loader was an implementation of IObjectFactoryLoader and would always just return null. Then the calls were forwarded to the server using the object factory there.

Sorry about the formatting. I don't know how to work these darn things.


.

Copyright (c) Marimer LLC