I noticed you have your own ICommand interface.

Jan 10, 2013 at 9:00 PM

Is there a reason you could not use the ICommand interface defined in the .Net framework or in Silverlight?

That kinda makes it a huge issue to use your existing commands along with this framework.

Coordinator
Jan 11, 2013 at 6:28 AM

The both commands represent different patterns. AFAIK the .NET ICommand should be bound to user controls. The Command in MCM has other purpose. It's a task, an operation or an action. It's executed in the background using CommandAsyncExecutor<TCommand> and after execution it stores the last exception - ICommand.Error. This way you'll create an asynchronous operation and you'll get notification after it completes.

        [MessageSubscriber(Env.MainMessageChannelName)]
        private void handleLoginRequestMessage(LoginRequestMessage m)
        {
            _loginCommandAsyncExecutor = new CommandAsyncExecutor<LoginCommand>();
            _loginCommandAsyncExecutor.ExecuteCompleted += on_loginCommandAsyncExecutor_ExecuteCompleted;

            // Each command has Argument and Result properties
            var arg = new LoginCommandArgument(m.Name, Env.Components.TimeProvider);
            var cmd = new LoginCommand(arg);

            _loginCommandAsyncExecutor.ExecuteAsync(cmd);
        }

        private void on_loginCommandAsyncExecutor_ExecuteCompleted(object sender, CommandEventArgs<LoginCommand> e)
        {
            var mes = new LoginResponseMessage(e.Command.Error);
            if (!mes.HasError)
            {
                // no error
                mes.Greeting = string.Format("{0}. It's {1}", e.Command.Result.Greeting,
                                            e.Command.Result.Now.ToLongTimeString());
            }

            Env.MainMessageChannel.Post(mes);
        }

Jan 11, 2013 at 6:36 PM

Ok, got it. Your commands are and alternative to System.Threading.Task. Is there a reason you don't use Task?

Here is essentially your same code just using Task and the Jounce  event aggregrator instead.

 

 

using Jounce.Core.Event;
using System;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;

namespace Example
{
    public class LoginRequestMessage { public string Name { get; set; } }
    public class LoginResult { public bool Success { get; set; } public string Message { get; set; } }
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class DeleteMe: Jounce.Core.Event.IEventSink<LoginRequestMessage>
    {
        [Import]
        public IEventAggregator EventAggregator { get; set; }

        public void OnImportsSatisfied()
        {
            EventAggregator.SubscribeOnDispatcher<LoginRequestMessage>(this);
        }

        public void HandleEvent(LoginRequestMessage m)
        {            
            var loginCommand = new Action(() =>
                {                    
                    if(m.Name != "polo")// Authenticate?
                    {
                        throw new Exception("Invalid credentials");
                    }
                });
             Task.Factory.StartNew(loginCommand)
                 .ContinueWith(theFinishedTask =>
                {
                    var mes = new LoginResult { Success = !theFinishedTask.IsFaulted};
                    if (!theFinishedTask.IsFaulted)
                    {
                        // no error
                        mes.Message = string.Format("{0}. It's {1}", m.Name, DateTime.Now.ToLongTimeString());
                    }
                    EventAggregator.Publish(mes);
                });
        }
    }
}

 

Jan 11, 2013 at 6:54 PM

Polo,

Can you give me a reason why I should use your framework over something like Jounce?

Thanks,

Aaron

Coordinator
Jan 11, 2013 at 8:13 PM

hi Aaron, I don't sell MCM and I'm not trying to convince you it's better than anything else. I have seen some frameworks starting with CAB & SCSF (Composite UI Application Block & the Smart Client Software Factory), XAF (eXpressApp Framework by DevExpress) ending with some MVVM implementations. They are powerful but slow, the configuration effort is immense, there are many rules and you need months to master them.

Creating MCM I had some goals: extensibility, testability, simplicity and as few rules as possible.

1. Extensibility

Using asynchronous message communication instead directly method invocation and referencing objects by interfaces i provide losse coupling - basis for extensibility. To extend the system you need only provide new components and connect them with the message channel - just like settle additional village residents.

2. Testability

Providing commands with arguments i isolate their environment. I can simulate each command parameter for unit tests.

3. Simplicity

An MCM Application consists only of a message channel (a loop in a dedicated thread) and components. Components subscribe the message channel, create commands for working and send messages. The whole rest you create on your own. The framework is small, so the learn effort is small. There is no overhead, you can freely and transparently create framework extensions.

Why do I use custom commands instead Threading.Tasks?

My command has some feature I personally like - instead providing the working method with a delegate I can inherit my command from a generic class and overwrite the ExecuteCore() method. It looks cleaner ;-)

Coordinator
Jan 11, 2013 at 9:16 PM
Edited Jan 13, 2013 at 6:35 AM
AustinHarris wrote:

Ok, got it. Your commands are and alternative to System.Threading.Task. Is there a reason you don't use Task?

Here is essentially your same code just using Task and the Jounce  event aggregrator instead.

(...)

Sorry, I don't know Jounce. The work result of your code could be the same but...

...using lambdas makes reading the code hard. The point is not writing the shortest code, but the best readable one. In your code you have mixed the component layer with the command layer. Component can access global variables and other services/components but command must be executed in an isolated environment closed in the command argument. Using commands as independent classes is crucial for unit tests.

Additionally I cannot use Theading.Task because MCM supports .NET 2.0 and Threading.Task exists since .NET 4.0.

The second thing - Can you tell me, why is using Threading.Task better than using the ThreadPool?

 

Below is the MCM representation of this task. Is it not easier to understand this code?

 

    public class LoginComponent
    {
        private CommandAsyncExecutor<LoginCommand> _loginCommandAsyncExecutor;

        [MessageSubscriber("MyMessages"]
        private void handleLoginRequestMessage(LoginRequestMessage m)
        {
            _loginCommandAsyncExecutor = new CommandAsyncExecutor<LoginCommand>();
            _loginCommandAsyncExecutor.ExecuteCompleted += on_loginCommandAsyncExecutor_ExecuteCompleted;

            var arg = new LoginCommandArgument(m.Name, Env.Components.TimeProvider);
            var cmd = new LoginCommand(arg);

            _loginCommandAsyncExecutor.ExecuteAsync(cmd);
        }

        private void on_loginCommandAsyncExecutor_ExecuteCompleted(object sender, CommandEventArgs<LoginCommand> e)
        {
            var mes = new LoginResponseMessage(e.Command.Error);
            if (!mes.HasError)
            {
                // no error
                mes.Greeting = string.Format("{0}. It's {1}", e.Command.Result.Greeting,
                                            e.Command.Result.Now.ToLongTimeString());
            }

            Env.MainMessageChannel.Post(mes);
        }
    }