Connectivity service interface in common library code - c#

I am working on a project that has a WPF and a mobile app, and there is also a .net standard library which has all the service and data layer which is shared between the two projects. I need to add a IConnectivityService Interface in the this common library project so that, before making a call to the server I can check if there is a connection available, and I also have an event handler in this interface that gets called when there is a change in connectivity.
public interface IConnectivityService
{
bool IsConnected { get; }
event EventHandler<ConnectivityChangedEventArgs> ConnectivityChanged;
}
The event handler for the Xamarin side do look like the above.
public interface IConnectivityService
{
bool IsConnected { get; }
event EventHandler ConnectivityChanged;
}
And for WPF it need to be this way.
Note: ConnectivityChangedEventArgs is a xamarin implementation and I would want to avoid from the shared code
Whats the best way to handle this? I ideally would like to have this as a shared code, so that I can use it in my service layer

Related

Show dialog from non UI dll

I'm building a dll that will be used from wpf and other kind of framework (windows form, asp...). For this reason I don't want to use Messagebox. Which is the best way to send notification from dll to app and each decide the way to show the message to user (and wait an answer from user)? Somebody can help me to find the correct way?
Unless the library (.dll) is only intended to work with a particular UI, the library shouldn't "decide" how or if notifications get displayed. It's a separation of concerns. If a library determined that it should show a MessageBox then you wouldn't be able to use that same library with a web app or some out-of-sight service.
Here are two ways (not exhaustive) that we might get information from a separate library, including our own:
We call a function and the library returns a response. For example, it might indicate that an action succeeded or failed. The library doesn't know what type of app it's being called from or whether anyone needs to see the response. It just returns it. Your app can then receive that result and display a message.
A class within the library raises an event which indicates that something has happened. Same thing - it doesn't know what is listening for that even or what will happen as a result. It just raises the notification. Our app determines that in response to that event it should display a message.
When our libraries work that way they are easier to test using automated tests like unit tests and integration tests. It's easy to write a test which verifies that calling a method returns a certain result. It's much harder to verify that a MessageBox pops up.
And, as mentioned, it makes it more likely that we can use more of our code with different types of user interfaces. For those reasons it's beneficial to write as much of our code as possible in isolation from any UI, which means not including input/output behaviors that are specific to one type of UI.
You could expose an event that the consumers can subscribe to. Here is the general pattern to do this kind of thing:
You can create your own class to carry the data about the event:
public class NotificationEventArgs : EventArgs
{
public NotificationEventArgs(string message)
{
Message = message;
}
public string Message { get; }
}
You then create a delegate to represent the signature of the event:
public delegate void OnNotificationEventHandler(SomeClass sender, NotificationEventArgs args);
Your class or classes can then expose this delegate as an event:
public class SomeClass
{
private OnNotificationEventHandler _notificationEventHandler;
public event OnNotificationEventHandler OnNotification
{
add { _notificationEventHandler += value; }
remove { _notificationEventHandler -= value; }
}
protected void RaiseNotificationEvent(NotificationEventArgs args)
{
_notificationEventHandler?.Invoke(this, args);
}
public void SomeMethod()
{
//Your class does something that requires consumer notification
var args = new NotificationEventArgs("Something happened!");
//Raise the event for the consumers who are listening (if any)
RaiseNotificationEvent(args);
}
}
Finally, your consuming classes will subscribe to this event:
SomeClass obj = new SomeClass();
obj.OnNotification += Obj_OnNotification;
private static void Obj_OnNotification(SomeClass sender, NotificationEventArgs args)
{
//Handle the notification from the class here.
Console.WriteLine(args.Message);
}
The general idea is that consumers of your class only need to know that something has happened as well as details of what happened. How that event is consumed, handled or displayed is not the responsibility of your component.

C# WPF Prism - Share a same object between different modules(project)

I have multiple modules(each module in a different project) in my prism project. And I would like to share a same object between each module.
For example, let say I have Order class and I would like to access this Order object in my modules.
Currently, I implemented an interface and registered it with container in my Prism project.
public interface ICommonService{
Order GetData();
}
public class CommonService : ICommonService{
public Order MyOrder{ get; set; }
public Order GetData(){
return MyOrder;
}
public void SetData(Order order){
MyOrder = order;
}
}
I am using it in every module where it need MyOrder.
Is this a correct way of sharing a same object between modules?
Also, my View Models classes contains several Manager classes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
I am trying to write clean and manageable code.
Thank you.
Is this a correct way of sharing a same object between modules?
Yes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
The manager classes are fine to use the service.
Notes:
You should include a means of notifying other consumers of ICommonService when MyOrder changes. Examples: implement INotifyPropertyChanged or publish a MyOrderChanged event through the event aggregator
Normally, anyone who can access a service (read: knows the interface), should be allowed to do so. It's better to restrict the accessibility of the interface (by putting it in a separate assembly) than restricting accessibility of the service (by documentation), because the former is enforced by the compiler.
You can use Event Aggregation
The Prism Library provides an event mechanism that enables communications between loosely coupled components in the application. This mechanism, based on the event aggregator service, allows publishers and subscribers to communicate through events and still do not have a direct reference to each other.
Link Communicating Between Loosely Coupled Components
Prism
Sample
When you define your module, you should specify an dependencies in the constructor for that module. For example:
public class SomeModule : IModule
{
public SomeModule(ICommonService commonService)
{
// commonService will be shared object
}
}
In your Bootstrapper, when you add the module to the catalog, it will look through the DI container to look up the type. If you have it set to global reference, it will use the same object for all references to ICommonService.
class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
RegisterTypeIfMissing(typeof(ICommonService),
typeof(CommonService), true); // true for register as singleton
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog module_catalog = (ModuleCatalog)this.ModuleCatalog;
module_catalog.AddModule(typeof(SomeModule));
}
}

C# COM server and client example

I have COM server with events implemented in C# and don't know how to write a C# client which hooks to events. I found several articles which describe how to do C# server and C++ clients but none (or I'm blind :-P ) which describe how to do the C# client using events. I'm able to connect to the COM server object but have no idea how to hook to the events.
Note I have two applications - one contains the C# COM server and another application which contains the C# client. The server is implemented as follows:
[ComVisible(true)]
[Guid("08214B02-512D-4785-9176-C4B4324FC340")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMyServer
{
bool Play(string sFile);
}
[ComVisible(true)]
[Guid("141CAAEA-63CE-422E-BF00-BAF4DBEEA77A")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyServerEvents
{
[DispId(1)]
event OnPlayFinishedHandler OnPlayFinished;
}
[ComVisible(true)]
[ProgId("MyApp.MyServer")]
[Guid("D184855D-E425-46A6-9171-34C828353778")]
[ComSourceInterfaces(typeof(IMyServerEvents))]
[ClassInterface(ClassInterfaceType.None)]
public class MyServer : IMyServer, IDisposable
{
public MyServer()
{
}
[ComVisible(false)]
public delegate void OnPlayFinishedHandler();
public event OnPlayFinishedHandler OnPlayFinished;
public bool Play(string sFile)
{
if (OnPlayFinished != null)
OnPlayFinished();
return true;
}
}
and now the client, I'm obtaining the COM server object via Running Object Table (not important I think here how).
IMyServer oServer = GetServer();
// TODO: Connect to OnPlayFinised event
oServer.Play("C://File.txt");
I tried to cast oServer to IMyServerEvents but it is not allowed.
As Hans said, you cannot add a COM reference if it's a .NET assembly. You have to add it as a normal assembly reference. Have you seen this MSDN example of implementing a C# COM server with events:
http://msdn.microsoft.com/en-us/library/dd8bf0x3(v=vs.90).aspx
Following from that MSDN example, you would then add that C# assembly as a reference in your C# client app. To hook into the events that the COM server raises, you'd write the event handler and then subscribe to the event. This sample code refers to the above MSDN example.
public void ClickEventHandler(int x, int y)
{
// The "Click" event was raised on the COM server, handle the event here
}
EventSource.Button myButton = new EventSource.Button();
myButton.Click += new EventSource.ClickDelegate(ClickEventHandler); // subscribe to the event

XAML C# Function across multiple windows

I've got a program I am working on that has multiple windows. The windows are similar in functionality and I want to have a single event handler to cover a button press event for each window in the application. Is this possible?
If you need to bind a handler in code behind you can encapsulate a handler by delegate and inject into the Windows which are required it.
For instance using Action<T>:
Action<string> commonHandler = (parameter) =>
{
// handler code here
};
class MyWindiow
{
public MyWindiow(Action<string> handler)
{
// store to local and assign to button click
// button.CLick += (o, e) => { handler(parameterToBepassed); }
}
}
I'd look into using a framework to help you out here. My favorite is Prism v4.
If you follow the M-V-VM design pattern you're life will be a lot easier. You'll need to understand Data Binding and DataContext.
That being said, if you decide to go this path, you can bind each of your windows to a command:
<Button Command="{Binding DoFooCommand}" Content="DoFoo"/>
You're ViewModel would have a DelegateCommand member to execute.
public class SomeViewModel : NotificationObject
{
public SomeViewModel()
{
DoFooCommand = new DelegateCommand(ExecuteFoo);
}
public DelegateCommand DoFooCommand { get; set; }
private void ExecuteFoo()
{
//Use the EventAggregator to publish a common event
}
}
And finally, somewhere else in your solution you'll have a code file/class that subscribes to the event and waits for someone to publish the event to process it.
public class SomeOtherPlace
{
public SomeOtherPlace()
{
//Use the EventAggregator to subscribe to the common event
}
public void FooBarMethodToCallWhenEventIsPublished(SomePayload payload)
{
//Do whatever you need to do here...
}
}
I realize some of the things were left out (such as what a "SomePayload" is... look into the EventAggregator information), but I did not want to get into it too much. Just give you a guide on where to go for information and some base code to work off of. If you decide to use the EventAggregator then you'll need to ensure that your subscribing call and publishing calls are utilizing the SAME instance of the EventAggregator. You can do this by looking into MEF. Prism is setup to work with MEF perfectly... I'm not going to lie. Doing all this requires a bit of a learning curve, but it will be worthwhile in the end when you can unit test your ViewModels easily and have your code loosely coupled. The EventAggregator is a great way for different classes to communicate to each other without relying on knowing about each other. And MEF is great for having a Container for your services that you want to utilize across your application.
Hope that gave you a bit of insight on how to go about doing what you want to do on the correct path.

Where to store application settings/state in a MVVM application

I'm experimenting with MVVM for the first time and really like the separation of responsibilities. Of course any design pattern only solves many problems - not all. So I'm trying to figure out where to store application state and where to store application wide commands.
Lets say my application connects to a specific URL. I have a ConnectionWindow and a ConnectionViewModel that support gathering this information from the user and invoking commands to connect to the address. The next time the application starts, I want to reconnect to this same address without prompting the user.
My solution so far is to create an ApplicationViewModel that provides a command to connect to a specific address and to save that address to some persistent storage (where it's actually saved is irrelevant for this question). Below is an abbreviated class model.
The application view model:
public class ApplicationViewModel : INotifyPropertyChanged
{
public Uri Address{ get; set; }
public void ConnectTo( Uri address )
{
// Connect to the address
// Save the addres in persistent storage for later re-use
Address = address;
}
...
}
The connection view model:
public class ConnectionViewModel : INotifyPropertyChanged
{
private ApplicationViewModel _appModel;
public ConnectionViewModel( ApplicationViewModel model )
{
_appModel = model;
}
public ICommand ConnectCmd
{
get
{
if( _connectCmd == null )
{
_connectCmd = new LambdaCommand(
p => _appModel.ConnectTo( Address ),
p => Address != null
);
}
return _connectCmd;
}
}
public Uri Address{ get; set; }
...
}
So the question is this: Is an ApplicationViewModel the right way to handle this? How else might you store application state?
EDIT: I'd like to know also how this affects testability. One of the primary reasons for using MVVM is the ability to test the models without a host application. Specifically I'm interested in insight on how centralized app settings affect testability and the ability to mock out the dependent models.
I generally get a bad feeling about code that has one view model directly communicating with another. I like the idea that the VVM part of the pattern should be basically pluggable and nothing inside that area of the code should depend of the existence of anything else within that section. The reasoning behind this is that without centralising the logic it can become difficult to define responsibility.
On the other hand, based on your actual code, it may just be that the ApplicationViewModel is badly named, it doesn't make a model accessible to a view, so this may simply be a poor choice of name.
Either way, the solution comes down to a break down of responsibility. The way I see it you have three things to achieve:
Allow the user to request to connect to an address
Use that address to connect to a server
Persist that address.
I'd suggest that you need three classes instead of your two.
public class ServiceProvider
{
public void Connect(Uri address)
{
//connect to the server
}
}
public class SettingsProvider
{
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
public class ConnectionViewModel
{
private ServiceProvider serviceProvider;
public ConnectionViewModel(ServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
public void ExecuteConnectCommand()
{
serviceProvider.Connect(Address);
}
}
The next thing to decide is how the address gets to the SettingsProvider. You could pass it in from the ConnectionViewModel as you do currently, but I'm not keen on that because it increases the coupling of the view model and it isn't the responsibility of the ViewModel to know that it needs persisting. Another option is to make the call from the ServiceProvider, but it doesn't really feel to me like it should be the ServiceProvider's responsibility either. In fact it doesn't feel like anyone's responsibility other than the SettingsProvider. Which leads me to believe that the setting provider should listen out for changes to the connected address and persist them without intervention. In other words an event:
public class ServiceProvider
{
public event EventHandler<ConnectedEventArgs> Connected;
public void Connect(Uri address)
{
//connect to the server
if (Connected != null)
{
Connected(this, new ConnectedEventArgs(address));
}
}
}
public class SettingsProvider
{
public SettingsProvider(ServiceProvider serviceProvider)
{
serviceProvider.Connected += serviceProvider_Connected;
}
protected virtual void serviceProvider_Connected(object sender, ConnectedEventArgs e)
{
SaveAddress(e.Address);
}
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
This introduces tight coupling between the ServiceProvider and the SettingsProvider, which you want to avoid if possible and I'd use an EventAggregator here, which I've discussed in an answer to this question
To address the issues of testability, you now have a very defined expectancy for what each method will do. The ConnectionViewModel will call connect, The ServiceProvider will connect and the SettingsProvider will persist. To test the ConnectionViewModel you probably want to convert the coupling to the ServiceProvider from a class to an interface:
public class ServiceProvider : IServiceProvider
{
...
}
public class ConnectionViewModel
{
private IServiceProvider serviceProvider;
public ConnectionViewModel(IServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
...
}
Then you can use a mocking framework to introduce a mocked IServiceProvider that you can check to ensure that the connect method was called with the expected parameters.
Testing the other two classes is more challenging since they will rely on having a real server and real persistent storage device. You can add more layers of indirection to delay this (for example a PersistenceProvider that the SettingsProvider uses) but eventually you leave the world of unit testing and enter integration testing. Generally when I code with the patterns above the models and view models can get good unit test coverage, but the providers require more complicated testing methodologies.
Of course, once you are using a EventAggregator to break coupling and IOC to facilitate testing it is probably worth looking into one of the dependency injection frameworks such as Microsoft's Prism, but even if you are too late along in development to re-architect a lot of the rules and patterns can be applied to existing code in a simpler way.
If you weren't using M-V-VM, the solution is simple: you put this data and functionality in your Application derived type. Application.Current then gives you access to it. The problem here, as you're aware, is that Application.Current causes problems when unit testing the ViewModel. That's what needs to be fixed. The first step is to decouple ourselves from a concrete Application instance. Do this by defining an interface and implementing it on your concrete Application type.
public interface IApplication
{
Uri Address{ get; set; }
void ConnectTo(Uri address);
}
public class App : Application, IApplication
{
// code removed for brevity
}
Now the next step is to eliminate the call to Application.Current within the ViewModel by using Inversion of Control or Service Locator.
public class ConnectionViewModel : INotifyPropertyChanged
{
public ConnectionViewModel(IApplication application)
{
//...
}
//...
}
All of the "global" functionality is now provided through a mockable service interface, IApplication. You're still left with how to construct the ViewModel with the correct service instance, but it sounds like you're already handling that? If you're looking for a solution there, Onyx (disclaimer, I'm the author) can provide a solution there. Your Application would subscribe to the View.Created event and add itself as a service and the framework would deal with the rest.
Yes, you are on the right track. When you have two controls in your system that need to communicate data, you want to do it in a way that is as decoupled as possible. There are several ways to do this.
In Prism 2, they have an area that is kind of like a "data bus". One control might produce data with a key that is added to the bus, and any control that wants that data can register a callback when that data changes.
Personally, I have implemented something I call "ApplicationState". It has the same purpose. It implements INotifyPropertyChanged, and anyone in the system can write to the specific properties or subscribe for change events. It is less generic than the Prism solution, but it works. This is pretty much what you created.
But now, you have the problem of how to pass around the application state. The old school way to do this is to make it a Singleton. I am not a big fan of this. Instead, I have an interface defined as:
public interface IApplicationStateConsumer
{
public void ConsumeApplicationState(ApplicationState appState);
}
Any visual component in the tree may implement this interface, and simply pass the Application state to the ViewModel.
Then, in the root window, when the Loaded event is fired, I traverse the visual tree and look for controls that want the app state (IApplicationStateConsumer). I hand them the appState, and my system is initialized. It is a poor-man's dependency injection.
On the other hand, Prism solves all of these problems. I kind of wish I could go back and re-architect using Prism... but it is a bit too late for me to be cost-effective.

Categories

Resources