[en] There is a strange thing. When I use Event happened. Triggered once the number of times an event is caused by uncertain times (solved)

Topics: Technical Support
Sep 27, 2013 at 10:10 AM
There is a strange thing. When I use Event happened. Triggered once the number of times an event is caused by uncertain times.

Server Code
public event Action<DataChangedEventArgs> PersonalChanged;

if (PersonalChanged != null)
            PersonalChanged(new DataChangedEventArgs(ChangedAction.Add, t.Id));

Client Code
_customerService.PersonalChanged += _customerService_PersonalChanged;


public int number = 1;
    void _customerService_PersonalChanged(DataChangedEventArgs obj)
    {
        number++;

    }
Sep 27, 2013 at 3:42 PM
I did a code alone have the same problem the code below
Event is triggered multiple times

int _eventedNumber = 0;
    ICommunication client; 
    public MainWindow()
    {
        InitializeComponent();
        var protocol = new TcpDuplexClientProtocolSetup(true);
        var credentials = new Hashtable();
        credentials.Add(AuthRequestMessage.CREDENTIAL_USERNAME, "Admin");
        credentials.Add(AuthRequestMessage.CREDENTIAL_PASSWORD, "Admin");
        credentials.Add(AuthRequestMessage.CREDENTIAL_DOMAIN, "ITJH");
        credentials.Add(AuthRequestMessage.CREDENTIAL_WINDOWS_SECURITY_TOKEN, "1"); 
        var conn = new ZyanConnection("tcpex://127.0.0.1:9999/ITJH", protocol, credentials,false,false );
        client = conn.CreateProxy<ICommunication>("Communication");
        client.Change += client_Change;
    } 
    void client_Change(DataChangedEventArgs e)
    {

        _eventedNumber++;
    } 
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        client.HeloWord("y");
        var actual = client.HeloWord("s"); 
    }

Server

/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        //创建服务
        var protocol = new TcpDuplexServerProtocolSetup(9999,
            new AuthenticationAppService(), true);
        var host = new ZyanComponentHost("ITJH", protocol);
        host.RegisterComponent<ICommunication>("Communication", () =>
        {
            return new Server();
        }); 
    }
}
public class Server : ICommunication
{ 
    public bool HeloWord(string s)
    {
        if (Change != null)
        {
            var arg = new DataChangedEventArgs(ChangedAction.Add, Guid.NewGuid());
            Change(arg);
        }
        return true;
    }

    public event Action<DataChangedEventArgs> Change;
} 
public class AuthenticationAppService : IAuthenticationProvider
{ 
    public AuthenticationAppService( )
    {

    }
    public AuthResponseMessage Authenticate(AuthRequestMessage authRequest)
    {
        if (authRequest == null)
            throw new ArgumentNullException("authRequest");
        if (authRequest.Credentials == null)
            throw new SecurityException("未提供有效的凭证");
        var account = authRequest.Credentials[AuthRequestMessage.CREDENTIAL_USERNAME].ToString();
        var password = authRequest.Credentials[AuthRequestMessage.CREDENTIAL_PASSWORD].ToString(); 
            return new AuthResponseMessage()
            { 
                Success = true
            }; 
    }
}
Sep 28, 2013 at 3:40 AM
I found this example code.
My client is a WPF and MVVM in one of the ViewModel.
I do not know how to implement such exclusion repeated calls.

private void _chatProxy_MessageReceived(string arg1, string arg2)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<string, string>(_chatProxy_MessageReceived), arg1, arg2);
            return;
        }

        _chatList.Items.Insert(0, string.Format("{0}: {1}", arg1, arg2));
    }
Sep 28, 2013 at 5:14 AM
The problem is the server using MEF container will trigger twice Event
Can help me find out the real reason?

host.RegisterComponent<INotification>("Notification", () =>
        {
            return container.GetExportedValue<INotification>();
            //return new NotificationService();
        });
Coordinator
Sep 29, 2013 at 12:00 AM
Edited Sep 29, 2013 at 12:01 AM
Hi youdontcay!

When you fire an event once, your event handler is invoked several times — right?
Sorry, I was unable to reproduce this behavior in my test project.
Could you please zip and upload the complete sample project so I can debug it in Visual Studio?
 
I found this example code. ... if (InvokeRequired) ...
 
This code is WinForms-specific.
When event handler needs to access the UI, we must ensure that it's executed within main UI thread.
That's why we call Control.Invoke method to create a marshaled callback.
For WPF, similar code will look like this:
TextBox.Dispatcher.Invoke(
    DispatcherPriority.Normal,
    () => TextBox.Text = "Event received!");
But this code has nothing to do with the repeated events.
Please help me with the sample project so I can nail down the issue.

Regards, yallie.
Coordinator
Sep 29, 2013 at 12:36 AM
Edited Sep 29, 2013 at 12:39 AM
I just reproduced the issue.
Looks like the source of the problem is your component registration:
host.RegisterComponent<INotification>("Notification", () =>
{
            return container.GetExportedValue<INotification>();
            //return new Notification();
});
I didn't investigate the problem in details yet, but I think that it goes like this.
You use RegisterComponent overload with a factory method to return a component instance.
When you use factory method, Zyan assumes that every time you'll return a fresh instance of the component.
For every new instance, we need to attach all event handlers before we use it to execute a remote call:
// Zyan dispatcher (pseudocode)
var instance = factory(); // create an instance of the component
instance.Event += eventHandler; // attach event handler
instance.ExecuteMethod(); // invoke remore method
But you don't create a new instance.
You just return whatever your container gives you with a GetExportedValue call.
Looks like it gives you the same instance it returned the last time.
Zyan reattaches event handlers again and again, so every time you'll get your handlers fired one extra time: twice, thrice, etc.

Here is a quick experiment: please try uncommenting your first version of the above code.
This version should run without repeated events:
host.RegisterComponent<INotification>("Notification", () =>
{
            return new Notification(); // not using container anymore!
});

The proposed solution

If you use MEF integration, please don't resolve your components manually.
Just use this overload to register all exported components at once:
// first, prepare your MEF catalog, i.e. new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
host.RegisterComponents(catalog); // register all Zyan components within the catalog
Let me know if it makes sense.
Marked as answer by yallie on 10/18/2013 at 4:06 AM