TCP packet consuming design issue for windows forms application - winforms

I am working on a TCP client application. I would like to share my problem and want to know the
better design approcah for packet consumed in application.
Currently I have designed it as:
Consumer class, is activated once it received packet from socket.
PacketReceived event is fired by consumer class once it recognized and build up a valid packet.
Now:
All my forms (and User controls) which need to consume packet, has subscribed for this event to
get notified and then consume packets for interest by checking speficic packetID.
The bad thing about this design is that, it need to write event subscriptuion code and packetID
verification code on every form (and user control).
Is there any better way to get the job done, please suggest.
I am using C#.net, Framework 3.5.
Thanks.
Muhammad Idrees

Sounds like you should use the observer pattern instead and let the consumer decide which packet to send where.
// implement this interface in all forms
public interface IPacketSubscriber
{
void HandlePacket(Packet packet);
}
// like this
public class SomeForm : Form, IPacketSubscriber
{
public SomeForm()
{
// subscribe in some way here.
YouSingleton.Consumer.Subscribe(1, this);
YouSingleton.Consumer.Subscribe(12, this);
YouSingleton.Consumer.Subscribe(25, this);
}
public void HandlePacket(Packet packet)
{
// got packet here
}
}
// Keeps track of all subscribers
public class SubscriberList
{
Dictionary<int, List<IPacketSubscriber>> _subscribers
= new Dictionary<int, List<IPacketSubscriber>>();
public void Subscribe(int packetId, IPacketSubscriber subscriber)
{
List<IPacketSubscriber> subscribers;
if (!_subscribers.TryGetValue(packetId, out subscribers))
{
subscribers = new List<IPacketSubscriber>();
_subscribers.Add(packetId, subscribers);
}
subscribers.Add(subscriber);
}
public void Publish(Packet packet)
{
List<IPacketSubscriber> subscribers;
if (!_subscribers.TryGetValue(packet.FunctionId, out subscribers))
{
subscribers = new List<IPacketSubscriber>();
_subscribers.Add(packet.FunctionId, subscribers);
}
foreach (var subscriber in subscribers)
{
subscriber.HandlePacket(packet);
}
}
}
// changes in the consumer class
// composite pattern & law of demeter, do not expose the subscriberlist
public class Consumer
{
SubscriberList _subscribers = new SubscriberList();
public void Subscribe(int packetId, IPacketSubscriber subscriber)
{
if (subscriber == null) throw new ArgumentNullException("subscriber");
_subscribers.Subscribe(packetId, subscriber);
}
protected void OnReceivedCompletePacket(Packet packet)
{
_subscribers.Publish(packet);
}
}
You can however decoupled things a bit more. The forms doesn't really have to know about the Consumer, only that they can receive events from somewhere. Let's use that knowledge and create another interface:
public interface IPacketDispatcher
{
void Subscribe(int packetId, IPacketSubscriber);
}
And then simply change so that the forms uses the interface instead (depends on how you expose the dispatcher/consumer to the forms).
That little change makes it very easy to test your forms and to change how you receive the packets in the future.

Related

Elegant way to handle exceptions in Test cases of MVVM Light's ViewModel

I am working on a wpf application using mvvm light toolkit. Whenever something goes outside the business logic we'll prompt the user with the message box and I send the message from view model to view using
Messenger.Default.Send(Token,"Some text message here");
Now I am writing test cases for view models and in some cases, Code Under Test is linked with such message calls. These are exceptions to me but test cases does not treat them exception as long as it is not being called by throw exception("message")
Suggestions.
Assuming you are sending message from VM to View, which handles the actual "showing logic", then just register for the message in your VM tests and verify that it has been sent/received. For example:
[TestMethod]
public void SendSomethingBadHappenedMessageTest()
{
const string expected = "oh noes!";
string actual = null;
// Register for message to ensure message was sent from VM
Messenger.Default.Register<SomethingBadHappenedMessage>(this,
message => actual = message.Message);
// Assuming command triggers Messenger.Send
_viewModel.SomethingBadHappenedCommand.Execute(expected);
Assert.AreEqual(expected, actual);
}
If you test for exceptions, just mark test method with ExpectedException attribute.
I assume you are trying to verify that the business logic detects a problem and the correct message box is being "shown" in your test case. If that's so, here's what I do:
Instead of using messaging, create a UserNotificationService and IUserNotificationService interface. The concrete implementation would be something like:
public class UserNotificationService : IUserNotificationService
{
public void MessageBox(string message)
{
// code to make the message box pop up goes here
}
}
Inject IUserNotificationService in your view model's constructor (you already have SimpleIoC since you are using mvvm-light) and use it to communicate with the user.
When unit testing, either mock the IUserNotificationService or create a new FakeUserNotificationService class that is capable of verifying the correct message/error was sent. Put that in the constructor of the view model being tested.
public class FakeUserNotificationService : IUserNotificationService
{
public void MessageBox(string message)
{
LastMessage = message;
}
public string LastMessage {get; set;}
}
In your test:
var ns = new FakeUserNotificationService();
var viewModel = new MyViewModel(ns);
viewModel.DoSomethingBad();
Assert.AreEqual(ns.LastMessage, "expected error message");

Notify property changed in WCF service

I have a WPF application which calls WCF service methods through a Client which exposes these methods. Is there any way to bind my application to a property of the service, and to get notified when this property changes? I know INotifyPropertyChanged but I have some doubts about its efficiency in this case... Thanks
EDIT : Actually, all I want is my application to be notified of the changes that happen on the server side.
There are a couple of questsions here. You can bind your code to the client end of a WCF service and by using a partial class definition you can add an INotifyPropertyChanged interface to it so that it meets your design. But actually wiring up the mechanism for pushing updates from the server would be much harder.
In fact, Events will work over WCF, and reasonably performant i.e. you won't have the delay associated with polling. However I wouldn't try to squeeze your WCF code into fitting the INotifyPropertyChanged pattern. Instead use a more bespoke interface for the client/server comms and then expose the INotifyPropertyChanged back in the ViewModel.
Just add a delegate to your service, then call the service from your view model or code behind and reflect the changes with your properties that implement the INotifyPropertyChanged interface:
In Service:
public delegate void ServcieUpdate(SomeDataType data);
public ServcieUpdate OnServcieUpdated { get; set; }
When data is updated:
if (OnServcieUpdated != null) OnServcieUpdated(data);
In view model:
private ServiceClient serviceClient = new ServiceClient();
private ObservableCollection<SomeDataType> data = new
ObservableCollection<SomeDataType>();
public YourViewModel()
{
serviceClient.OnServiceUpdated += OnServcieUpdated;
}
public ObservableCollection<SomeDataType> Data
{
get { return data; }
set { data = value; NotifyPropertyChanged("Data");
}
public void OnServcieUpdated(SomeDataType data)
{
Data = data;
}
Please take a look at the Delegates (C# Programming Guide) page on MSDN in you are unfamiliar with using delegate objects.

EJB 3.1 and NIO2: Monitoring the file system

I guess most of us agree, that NIO2 is a fine thing to make use of. Presumed you want to monitor some part of the file system for incoming xml - files it is an easy task now. But what if I want to integrate the things into an existing Java EE application so I don't have to start another service (app-server AND the one which monitors the file system)?
So I have the heavy weight app-server with all the EJB 3.1 stuff and some kind of service monitoring the file system and take appropriate action once a file shows up. Interestingly the appropriate action is to create a Message and send it by JMS and it might be nice to integrate both into the app server.
I tried #Startup but deployment freezes (and I know that I shouldn't make use of I/O in there, was just a try). Anyhow ... any suggestions?
You could create a singleton that loads at startup and delegates the monitoring to an Asynchronous bean
#Singleton
#Startup
public class Initialiser {
#EJB
private FileSystemMonitor fileSystemMonitor;
#PostConstruct
public void init() {
String fileSystemPath = ....;
fileSystemMonitor.poll(fileSystemPath);
}
}
Then the Asynchronous bean looks something like this
#Stateless
public class FileSystemMonitor {
#Asynchronous
public void poll(String fileSystemPath) {
WatchService watcher = ....;
for (;;) {
WatchKey key = null;
try {
key = watcher.take();
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue; // If events are lost or discarded
}
WatchEvent<Path> watchEvent = (WatchEvent<Path>)event;
//Process files....
}
} catch (InterruptedException e) {
e.printStackTrace();
return;
} finally {
if (key != null) {
boolean valid = key.reset();
if (!valid) break; // If the key is no longer valid, the directory is inaccessible so exit the loop.
}
}
}
}
}
Might help if you specified what server you're using, but have you considered implementing a JMX based service ? It's a bit more "neutral" than EJB, is more appropriate for a background service and has fewer restrictions.

Mvvm Light Messenger message never recieved

I have a strange problem.
I'm using the MVVM Light framework from GalaSoft and everything so far works fine.
I'm using the messenger system to send messages between ViewModels just fine, until I tried to do the following:
I have a singleton class, GateKeeper, that sends messages.
This class is NOT a ViewModel and thus does not inherit from ViewModelBase.
If it sends a message it is not received anywhere.
I have tried the following:
Letting GateKeeper inherit from ViewModeBase -> No success.
Registering GateKeeper to receive messages, thus seeing if it would catch/receive the message that was actually sent from itself -> No Success.
Changing GateKeeper from Singleton to normal instantiation -> no Success
Creating a MVVM ViewModel that is not connected to a view, and letting it send messages, just like the GateKeeper -> no Success
All my viewModels that are connected to a view can send messages and they will be received.
It almost seems like a viewmodel must be "linked" to a view before the messenger works,but imo. that is a major limitation.
Below is the current, very simplified setup.
Calling ApplicationInitialize on GateKeeper does not trigger a message received on the mainviewmodel nor the GateKeeper class itselves.
I hope that someone has suggestions to this problem.
Thanks..
Example setup:
MainViewModel constructor:
public MainViewModel()
{
Messenger.Default.Register<LoadViewMessage>(this, (message) =>
{
if (message.Sender is GateKeeper) CurrentView = message.View;
else if (message.Sender is LoginViewModel) CurrentView = message.View;
else if (message.Sender is MenuItemBarViewModel) CurrentView = message.View;
});
GateKeeper:
public class GateKeeper : IGateKeeper
{
private readonly IEmployeeService _employeeService;
#region Implementation of IGateKeeper
public void ApplicationInitialize()
{
Messenger.Default.Send<LoadViewMessage>(new LoadViewMessage(ObjectLocator.MainMapView), this);
}
public void LoginSucceeded(Employee employee)
{
//This is where we retrieve the available services for the current employee
//TODO: add methods for retrieving service info from backend
//Send a message that should make the mainview load the map into its currentview property
Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView), this);
}
#endregion
public GateKeeper(IEmployeeService employeeService)
{
_employeeService = employeeService;
//Test.. Is not triggered
//Just used for debugging, thus nothing happens inhere.
Messenger.Default.Register<LoadViewMessage>(this, (message) =>
{
if (message.Sender is GateKeeper) ;
else if (message.Sender is LoginViewModel) ;
else if (message.Sender is MenuItemBarViewModel);
});
}
Message class: LoadViewMessage
public class LoadViewMessage : MessageBase
{
public UserControl View { get; protected set; }
public LoadViewMessage(UserControl view, object sender): base(sender)
{
View = view;
}
public LoadViewMessage(UserControl view):this(view, null){}
}
PS: ObjectLocator is a NinJect class that handles all instantiation of objects and their lifecycle
#UPDATE
LBugnion (Creator of MVVM Light) pointed out that the problem lied in the send method, where i was actually using a overload of Send that takes a token.
#This will not work in my situation
Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView), this);
#This WILL work
Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView, this));
this was supposed to be passed to the loadViewMessage and NOT the Send method as a token
Your problem is on the Send method. You are using the overload of the method that takes a token as second parameter. You are passing "this" as token. It means that you are (probably by mistake) using the sender of the message as token.
If you are sending with a token, you also need to register the receiver with the same token (in that case, the exact same instance than the one used in the Send method). Since you didn't register with a token, the message is never sent by the Messenger, which is an optimization mechanism.
My guess is that you misunderstood the usage of the token in the Send method. Tokens are only here as a way to build a "private messenging network" if you want, where two objects can use the same token to register/send and establish a private communication.
In your case, if you want to send the Sender together with the message, you'll need to save the Sender in the message itself, which is what MessageBase and the derived classes do.
Hope this helps
Laurent

Run code on UI thread without control object present

I currently trying to write a component where some parts of it should run on the UI thread (explanation would be to long).
So the easiest way would be to pass a control to it, and use InvokeRequired/Invoke on it.
But I don't think that it is a good design to pass a control reference to a "data/background"-component, so I'm searching for a way to run code on the UI thread without the need of having a control available.
Something like Application.Dispatcher.Invoke in WPF...
any ideas,
thx
Martin
There's a better, more abstract way to do this that works on both WinForms and WPF:
System.Threading.SynchronizationContext.Current.Post(theMethod, state);
This works because WindowsForms installs a WindowsFormsSynchronizationContext object as the current sync context. WPF does something similar, installing it's own specialized synchronization context (DispatcherSynchronizationContext).
.Post corresponds to control.BeginInvoke, and .Send corresponds to control.Invoke.
First, in your form constructor, keep a class-scoped reference to the SynchronizationContext.Current object (which is in fact a WindowsFormsSynchronizationContext).
public partial class MyForm : Form {
private SynchronizationContext syncContext;
public MyForm() {
this.syncContext = SynchronizationContext.Current;
}
}
Then, anywhere within your class, use this context to send messages to the UI:
public partial class MyForm : Form {
public void DoStuff() {
ThreadPool.QueueUserWorkItem(_ => {
// worker thread starts
// invoke UI from here
this.syncContext.Send(() =>
this.myButton.Text = "Updated from worker thread");
// continue background work
this.syncContext.Send(() => {
this.myText1.Text = "Updated from worker thread";
this.myText2.Text = "Updated from worker thread";
});
// continue background work
});
}
}
You will need the following extension methods to work with lambda expressions: http://codepaste.net/zje4k6
You are right, it is not good to pass controls to threads. Winforms controls are single-threaded, passing them to multiple threads can cause race conditions or break your UI. Instead, you should make your thread's features available to the UI and let it call the thread when the UI is good and ready. If you want to have background threads trigger UI changes, expose a background event and subscribe to it from the UI. The thread can fire off events whenever it wants and the UI can respond to them when it is able to.
Creating this bidirectional communication between threads that does not block the UI thread is a lot of work. Here is a highly abbreviated example using a BackgroundWorker class:
public class MyBackgroundThread : BackgroundWorker
{
public event EventHandler<ClassToPassToUI> IWantTheUIToDoSomething;
public MyStatus TheUIWantsToKnowThis { get { whatever... } }
public void TheUIWantsMeToDoSomething()
{
// Do something...
}
protected override void OnDoWork(DoWorkEventArgs e)
{
// This is called when the thread is started
while (!CancellationPending)
{
// The UI will set IWantTheUIToDoSomething when it is ready to do things.
if ((IWantTheUIToDoSomething != null) && IHaveUIData())
IWantTheUIToDoSomething( this, new ClassToPassToUI(uiData) );
}
}
}
public partial class MyUIClass : Form
{
MyBackgroundThread backgroundThread;
delegate void ChangeUICallback(object sender, ClassToPassToUI uiData);
...
public MyUIClass
{
backgroundThread = new MyBackgroundThread();
// Do this when you're ready for requests from background threads:
backgroundThread.IWantTheUIToDoSomething += new EventHandler<ClassToPassToUI>(SomeoneWantsToChangeTheUI);
// This will run MyBackgroundThread.OnDoWork in a background thread:
backgroundThread.RunWorkerAsync();
}
private void UserClickedAButtonOrSomething(object sender, EventArgs e)
{
// Really this should be done in the background thread,
// it is here as an example of calling a background task from the UI.
if (backgroundThread.TheUIWantsToKnowThis == MyStatus.ThreadIsInAStateToHandleUserRequests)
backgroundThread.TheUIWantsMeToDoSomething();
// The UI can change the UI as well, this will not need marshalling.
SomeoneWantsToChangeTheUI( this, new ClassToPassToUI(localData) );
}
void SomeoneWantsToChangeTheUI(object sender, ClassToPassToUI uiData)
{
if (InvokeRequired)
{
// A background thread wants to change the UI.
if (iAmInAStateWhereTheUICanBeChanged)
{
var callback = new ChangeUICallback(SomeoneWantsToChangeTheUI);
Invoke(callback, new object[] { sender, uiData });
}
}
else
{
// This is on the UI thread, either because it was called from the UI or was marshalled.
ChangeTheUI(uiData)
}
}
}
Put the UI manipulation in a method on the form to be manipulated and pass a delegate to the code that runs on the background thread, à la APM. You don't have to use params object p, you can strongly type it to suit your own purposes. This is just a simple generic sample.
delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
if (InvokeRequired)
BeginInvoke(d,p);
else
{
//do stuff to UI
}
}
This approach is predicated on the fact that a delegate refers to a method on a particular instance; by making the implementation a method of the form, you bring the form into scope as this. The following is semantically identical.
delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
if (this.InvokeRequired)
this.BeginInvoke(d,p);
else
{
//do stuff to UI
}
}
What about passing a System.ComponentModel.ISynchronizeInvoke? That way you can avoid passing a Control.

Resources