How to access a service from a GUI - c#

I have a program for collecting files from networked computers and storing them to local directories. This is done hourly, I am looking to make this into a service that will run in the background, BUT have a small app running that makes a systemtray icon, this icon would allow the user to open a GUI where they can modify the location to save the files to and the location to retrieve the files from, as well as do a manual collection of files for a user defined dateTime range. I am curious if the GUI is just a front end and all the 'heavy-lifting' methods are done in the service how can I access those service functions from GUI?
for example if the below was my service(very crude version):
partial class RemoteArchiveService : ServiceBase
{
...
...
string destination;
string retrieveFrom;
List<string> fileNames;
public void ChangeCollectFrom(string filepath){...}
public void ChangeDestinationFolder(string filepath){...}
public void GetFilesAsynchronously(){...}
...
...
}
in the GUI code how could I access the function ChangeCollectionFrom() with a new user input string?

Look into WCF and make your GUI a client that calls into the service. A good place to start would be http://msdn.microsoft.com/en-us/library/ms733069.aspx
WCF will allow you to cleanly and concisely specify the methods that a client will need to access by hosting a WCF service in your existing windows service. For example you could do something like the following:
[ServiceContract(Namespace = "http://Somewhere.StackOverflow.Samples")]
public interface IRemoteArchive
{
[OperationContract]
void ChangeCollectionFrom(string filepath);
}
partial class RemoteArchiveWCFService : IRemoteArchive
{
public void ChangeCollectionFrom(string filepath)
{
// ...
}
}
And then elsewhere in your RemoteArchiveService ( snippet taken from link above )
partial class RemoteArchiveService : ServiceBase
{
// ...
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(RemoteArchiveWCFService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
// ...
}

Nowadays, most of services expose a Web UI for configuration and administration like Oracle, Network-enabled printers, etc., so I recommend you take advantage of Web UI for your purpose and the happy news is that it's not very difficult.
Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .Net and Mono which can help you in this way.
In addition, Build Simple Web UIs with the Nancy Framework is a great article that exactly describes what you want.

Related

How to pass data to injected services

I want to code a small WinForms or WPF program that controls that only one person/computer a time uses a specific shared file through a network share. This file needs to be copied locally when working and copied back to the network share when the work is finished.
I want to create a small WPF application with only one button to flag the file as locked, copy it locally and open the application associated to that file extension. When this application is closed, the file is copied back to the network share and the lock is released. Each computer will use this application to access the file, so it should never be two computers editing the same file at the same time.
The application has to have some kind of configuration file with the path for local and remote folders, the name of the file and the path of the application to open that file. To ease setting up the application it will be done with a SettingsWindow.
I am trying to do it with IoC and some kind of lightweight DI container (i.e. SimpleInjector), but I am having some questions about how to do it properly:
Program.cs
static class Program
{
[STAThread]
static void Main()
{
var container = Bootstrap();
// Any additional other configuration, e.g. of your desired MVVM toolkit.
RunApplication(container);
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types, for instance:
container.Register<ILauncher, Launcher>();
container.Register<IFileSyncService, FileSyncronizer>();
container.Register<IAppRunnerService, AppRunnerService>();
container.Register<ILockService, LockService>();
// Register your windows and view models:
container.Register<MainWindow>();
container.Register<ConfigurationWindow>();
container.Verify();
return container;
}
private static void RunApplication(Container container)
{
try
{
var app = new App();
var mainWindow = container.GetInstance<MainWindow>();
app.Run(mainWindow);
}
catch (Exception ex)
{
//Log the exception and exit
}
}
}
MainWindow
I modified the constructor to receive an interface ILauncher that will be resolved by the DI container.
public partial class MainWindow : Window
{
public MainWindow(ILauncher launcher)
{
InitializeComponent();
}
…
}
ILauncher interface
public interface ILauncher
{
void Run();
}
Launcher implementation
The launcher implementation will take care of coordinating every task needed to launch the application and edit the file. This consists of: checking and acquiring the lock, synchronizing the file, executing and monitoring that the application has been closed. To follow the Single Responsibility Principle (SRP) this is done through some services injected:
public class Launcher : ILauncher
{
public Launcher(
ILockService lockService,
IAppRunnerService appRunnerService,
IFileSyncService fileSyncService
)
{
LockService = lockService;
AppRunnerService = appRunnerService;
FileSyncService = fileSyncService;
}
public ILockService LockService { get; }
public IAppRunnerService AppRunnerService { get; }
public IFileSyncService FileSyncService { get; }
public void Run()
{
//TODO check lock + adquire lock
//TODO Sinchronize file
//TODO Subscribe to the IAppRunnerService.OnStop event
//TODO Start app through IAppRunnerService.Run method
}
}
My questions:
Creating new instances with the “new” keyword or with manual calls to the container inside classes or windows is a bad practice, so the entry point of the desktop application (usually some kind of a main window) should ask (via the constructor) for everything. It doesn’t seem a proper way when the application grows. Am I right? What is the solution?
In my application, every service needs some kind of runtime data (the executable file path, the local or remote directory…). The container instantiates them early in the application execution, even before this data is known. How can the services receive this data? (Please note that data could be modified later by the SettingsWindow).
Sorry for the extension of this post but I wanted to make my problem and the context clear.
As you've said, you have to ask for some services in the entry point, but what do you mean ask for everything? Your entry point should have only the services it directly uses speciifed as ctor parameters. If your application grows and you suddenly have a dozen services called directly by your entry point - that could indicate that some of the services could be consolidated into a bigger packet. That's opinion-based territory though, as long as you consider it maintainable it's okay.
Many possible solutions here, one would be an ISettingsManager allowing for realtime access to the settings across any services that take it as a dependency.

WCF hosted in WPF and how can i change control in MainWindow UI from wcf?

I write WCF code and hosted in my WPF app.
I write class to switch my MainWindow to show other page in my project
public static class Switcher
{
public static MainWindow pageSwitcher;
public static void Switch(Page newPage)
{
pageSwitcher.Navigate(newPage);
}
}
and I write my wcf service like this:
[ServiceContract]
public interface IAppManager
{
[OperationContract]
void DoWork();
[OperationContract]
void Page1();
[OperationContract]
void Page2();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class AppManager : IAppManager
{
public void DoWork()
{
}
public void Page1()
{
MainWindow.pageSwitcher = new MainWindow();
MainWindow.Switch(new Page1());
}
public void Page2()
{
MainWindow.pageSwitcher = new MainWindow();
MainWindow.Switch(new Page2());
}
}
I want change page remotely from another computer with WCF but it not work
and I trace code the wcf is run and response but do not do anything
how can access to main thread to change ui page or other element?
Your current solution is unusual, but WCF can be hosted in a WPF application. However you should never try to directly manipulate the UI from the WCF service - you'll have cross thread issues to begin with.
What you should consider doing is using messaging via a pub-sub broker (image linked from MSDN):
Something that fits this bill nicely is Prism's EventAggregator. A couple of samples I cherry picked are Simplifying PRISM’s EventAggregator and Prism EventAggregator Sample.
The way you use this is the service registers events and then raises them, the WPF subscribes to those events and processes them. With this you can also specify whether to receive the events on the UI thread or a background thread.
I suggest you start over and this time separate the WCF from your WPF app.
You need to:
1) Separate WCF from WPF - should be in different layers.
2) Use WCF with duplex binding - this way your WCF service will be able to communicate with clients when it needs to.
3) In your WCF callback contract (implemented by the client) - you should prepare a method that will be used to change the local UI mode.
Duplex binding is the perfect solution for your needs.
You can reed about Duplex here
Hope I helped!
Eking.

IIS hosted WCF service: Integration tests and code coverage

For a project I have programmed a wcf service library. It can be hosted in IIS and in a self-hosted service.
For all external systems that are connected, I have provided Mock implementations which give some generic data, so such the service (library) keeps running and doing work. It is a classic automaton / finite-state machine.
While bootstrapping, all data sources are connected. In testing mode, the mock implementations are connected. So when I run tests, the service library is "started" from a self-hosted service, not IIS and the the state machine keeps running and processing data packages.
Is there any way to get some kind of "test coverage" from such a run.
I would really appreciate if I could tell which code paths are hit by the example data I provide from the mock objects. And then provide more testdata to get a higher coverage.
If I could do this without having to provide "lots of extra" testing code, it would be great. I think a lot of cases are already covered from the data provided from the mock objects. But right now I have no starting point for that.
Here are some code examples to give a more clear picture of what is meant. Code is strongly simplified of course.
In a very simple console application to start the service (self hosted version)
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(MyServiceLib.Service.MyServiceLib)))
{
host.Open();
Console.ReadLine();
host.Close();
}
}
In the service library, a constructor is called from that code
public MyServiceLib()
{
Task.Factory.StartNew(this.Scaffold);
}
Which does nothing more than starting the state machine
private void Scaffold()
{
// lots of code deleted for simplicity reasons
var dataSource = new MockDataSource();
// inject the mocked datasource
this.dataManager = new DataManager(dataSource);
// this runs in its own thread. There are parts that are started on a timer event.
this.dataManager.Start();
}
public class DataManager : IDataManager
{
public void Start()
{
while (this.IsRunning)
{
var data = this.dataSource.getNext();
if (data != null)
{
// do some work with the data retrieved
// lots of code paths will be hit from that
this.Process(data);
}
else
{
Thread.Sleep(1000);
}
}
}
public void Process(IData data)
{
switch (data.PackageType)
{
case EnumPackageType.Single:
{
ProcessSingle(data);
break;
}
case EnumPackageType.Multiple:
{
ProcessMultiple(data);
break;
}
// here are lots of cases
default:
{
Logger.Error("unknown package type");
break;
}
}
}
}
What I have tried so far:
OpenCover
with a special test dll that would create the Host as shown above, but the host cannot be created properly, so the testing does not start really. I get a "Host is in fault state" error message. I followed this mini-tutorial. Despite that I get a coverage report with a calculated coverage of about 20%. But the service is just starting, it is not doing any work so far.
Visual Studio Performance Tools
The steps are essentially described in this article. I get a myproject.coverage file, but I cannot view it, because I only have a VS Professional, the coverage seems to be only of use in Test Premium or Ultimate editions.
Besides having tried those two, I will accept any answer showing how to get it up and running with any of those (openCover preferred).
Will accept an answer that shows how to test this setup and get a code coverage while leveraging tools to generate most of the code (as pex would, but after trial I see it does not generate very good code).
It would help to see the operations of the service.
I never tried running such "console kind" application under a coverage tool.
I would suggest writing a test with let's say NUnit (or any other unit testing framework; it's not a unit test, obviously, but the technique fits quite well).
In the test, you open the service host, create a client of the service, let the client execute some operations on your service, and close the service host.
Run this test under a coverage tool, and you should be done.
I've done that with NUnit and NCover about 7 years ago, using their current versions at that time (NCover was free software, if I remember it right).
Looks like with OpenCover you are actually getting the coverage, but the service is entering Faulted state, so to you need to catch the faults from your ServiceHost and adress that.
Basically you need some kind of error log, and the first thing i would try is looking in the system event logs (Win+R, eventvwr.msc, Enter).
You can also try to listen to the Faulted events on your ServiceHost:
host.Faulted += new EventHandler(host_faulted);
Here is the link to another SO answer addressing this issue:
How to find out the reason of ServiceHost Faulted event
I would suggest testing your business logic and not the bootstrap code. I mean testing DataManager class and not the hosting and the initializing code. You can write a unit test, using one of the unit testing frameworks, for example NUnit. Then you can run your tests either in Visual Studio with Resharper Ultimate or in your Continuous Integration with Code Coverage tool, like OpenCover or dotCover to get your code coverage.
[TestFixture]
public class DataManagerTests
{
[Test]
public void Process_Single_Processed()
{
// Arrange
IData data = new SingleData();
DataManager dataManager = new DataManager();
// Act
dataManager.Process(data);
// Assert
// check data processed correctly
}
}
in order to allow your Unit-Test-Framework to determin the coverage you have to host the service within the "runner" of the framework (aka. the process that is executing the tests).
The coverage is calculated by and withing the "runner" what means that you can not get coverage if the service is hosted anywhere else.
Below I'll add an example how to do this.
Greetings
Juy Juka
namespace ConsoleApplication4
{
using System.ServiceModel; // Don't forgett to add System.ServiceModel as Reference to the Project.
public class Program
{
static void Main(string[] args)
{
string arg = ((args != null && args.Length > decimal.Zero ? args[(int)decimal.Zero] : null) ?? string.Empty).ToLower(); // This is only reading the input for the example application, see also end of Main method.
string randomUrl = "net.tcp://localhost:60" + new System.Random().Next(1, 100) + "/rnd" + new System.Random().Next(); // random URL to allow multiple instances parallel (for example in Unit-Tests). // Better way?
if (arg.StartsWith("t"))
{
// this part could be written as a UnitTest and should be
string result = null;
using (ServiceHost host = new ServiceHost(typeof(MyService)))
{
host.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding(), randomUrl);
host.Open();
IMyService instance = ChannelFactory<IMyService>.CreateChannel(new NetTcpBinding(), new EndpointAddress(randomUrl), null);
result = instance.GetIdentity();
host.Close();
}
// Assert.Equals(result,"Juy Juka");
}
else if (arg.StartsWith("s"))
{
// This part runs the service and provides it to the outside. Just to show that it is a real and working host. (and not only working in a Unit-Test)
using (ServiceHost host = new ServiceHost(typeof(MyService)))
{
host.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding(), randomUrl);
host.Open();
System.Console.Out.WriteLine("Service hosted under following URL. Terminate with ENTER.");
System.Console.Out.WriteLine(randomUrl);
System.Console.In.ReadLine();
host.Close();
}
}
else if (arg.StartsWith("c"))
{
// This part consumes a service that is run/hosted outoside of the application. Just to show that it is a real and working host. (and not only working in a Unit-Test)
System.Console.Out.WriteLine("Please enter URL of the Service. Execute GetIdentity with ENTER. Terminate with ENTER.");
IMyService instance = ChannelFactory<IMyService>.CreateChannel(new NetTcpBinding(), new EndpointAddress(System.Console.In.ReadLine()), null);
System.Console.Out.WriteLine(instance.GetIdentity());
System.Console.In.ReadLine();
}
else
{
// This is only to explain the example application here.
System.Console.Out.WriteLine("I don't understand? Please use one of the following (Terminate this instance with ENTER):");
System.Console.Out.WriteLine("t: To host and call the service at once, like in a UnitTest.");
System.Console.Out.WriteLine("s: To host the servic, waiting for clients.");
System.Console.Out.WriteLine("c: To contact a hosted service and display it's GetIdenttity result.");
System.Console.In.ReadLine();
}
}
}
// Declaration and Implementation of the Service
[ServiceContract]
public interface IMyService
{
[OperationContract]
string GetIdentity();
}
public class MyService : IMyService
{
public string GetIdentity()
{
return "Juy Juka";
}
}
}

Dealing with concurrency and complex WCF services interacting with objects of the overall application

I am enjoying creating and hosting WCF services.
Up until now I can create services defining contracts for the service and data (interfaces) and defining hosts and configuration options to reach them (endpoint specifications).
Well, consider this piece of code defining a service and using it (no mention for endpoints that are defined in app.config not shown here):
[ServiceContract]
public interface IMyService {
[OperationContract]
string Operation1(int param1);
[OperationContract]
string Operation2(int param2);
}
public class MyService : IMyService {
public string Operation1(int param1) { ... }
public string Operation2(int param2) { ... }
}
public class Program {
public static void Main(stirng[] args) {
using (ServiceHost host = new ServiceHost(typeof(MyService))) {
host.Open();
...
host.Close();
}
}
}
Well, this structure is good when creating something that could be called a Standalone service.
What if I needed my service to use objects of a greater application.
For example I need a service that does something basing on a certain collection defined somewhere in my program (which is hosting the service). The service must look into this collection and search and return a particular element.
The list I am talking about is a list managed by the program and edited and modified by it.
I have the following questions:
1) How can I build a service able to handle this list?
I know that a possible option is using the overloaded ServiceHost constructor accepting an Object instead of a Type service.
So I could pass my list there. Is it good?
[ServiceContract]
public interface IMyService {
[OperationContract]
string Operation1(int param1);
[OperationContract]
string Operation2(int param2);
}
public class MyService : IMyService {
private List<> myinternallist;
public MyService(List<> mylist) {
// Constructing the service passing the list
}
public string Operation1(int param1) { ... }
public string Operation2(int param2) { ... }
}
public class Program {
public static void Main(stirng[] args) {
List<> thelist;
...
MyService S = new MyService(thelist)
using (ServiceHost host = new ServiceHost(S)) {
host.Open();
...
host.Close();
// Here my application creates a functions and other that manages the queue. For this reason my application will edit the list (it can be a thread or callbacks from the user interface)
}
}
}
This example should clarify.
Is it the good way of doing? Am I doing right?
2) How to handle conflicts on this shared resource between my service and my application?
When my application runs, hosting the service, my application can insert items in the list and delete them, the same can do the service too. Do I need a mutex? how to handle this?
Please note that the concurrency issue concerns two actors: the main application and the service. It is true that the service is singleton but the application acts on the list!!!
I assume that the service is called by an external entity, when this happens the application still runs right? Is there concurrency in this case???
Thankyou
Regarding point 2, you can use Concurrent Collections to manage most of the thread safety required.
I'm not sure what you mean by point 1. It sounds like you're describing basic polymorphism, but perhaps you could clarify with an example please?
EDIT: In response to comments you've made to Sixto's answer, consider using WCF's sessions. From what you've described it sounds to me like the WCF service should be sat on a seperate host application. The application you are using currently should have a service reference to the service, and using sessions would be able to call an operation mimicking your requirement for instantiating the service with a list defined by the current client application.
Combine this with my comment on exposing operations that allow interaction with this list, and you'll be able to run multiple client machines, working on session stored Lists?
Hope that's explained well enough.
Adding the constructor to MyService for passing the list certainly will work as you'd expect. Like I said in my comment to the question however, the ServiceHost will only ever contain a single instance of the MyService class so the list will not be shared because only one service instance will consume it.
I would look at a dependency injector (DI) container for WCF to do what you are trying do. Let the DI container provide the singleton list instance to your services. Also #Smudge202 is absolutely correct that using the Concurrent Collection functionality is what you need to implement the list.
UPDATE based on the comments thread:
The DI approach would works by getting all of an object's dependencies from the DI container instead of creating them manually in code. You register all the types that will be provided by the container as part of the application start up. When the application (or WCF) needs a new object instance it requests it from the container instead of "newing" it up. The Castle Windsor WCF integration library for example implements all the wiring needed to provide WCF a service instance from the container. This posts explains the details of how to use the Microsoft Unity DI container with WCF if you want to roll your own WCF integration.
The shared list referenced in this question would be registered in the container as an already instantiated object from your application. When a WCF service instance is spun up from the DI container, all the constructor parameters will be provided including a reference to the shared list. There is a lot of information out there on dependency injection and inversion of control but this Martin Fowler article is a good place to start.

difference in consume WCF service - Console vs Silverlight

Can someone tell my why when I have wcf contract:
[ServiceContract]
public interface IService1
{
[OperationContract]
string TestGetName();
}
and implementation
public string TestGetName()
{
return "Kasia";
}
When I try consume it in Console app I can do just that:
Service1Client client = new Service1Client();
Console.WriteLine((client.TestGetName()));
but in Silverlight I must use that way :
Service1Client clientTest = new Service1Client();
clientTest.TestGetNameCompleted += new EventHandler<TestGetNameCompletedEventArgs>(clientTest_TestGetNameCompleted);
clientTest.TestGetNameAsync();
void clientTest_TestGetNameCompleted(object sender, TestGetNameCompletedEventArgs e)
{
this.dataGridChild.DataContext = e.Result;
}
Why in SL I don't see this first short solution, but only this with Event handlers?
Or better... why in Console app I can choose synchro operation generation and in SL I must use Generate asynchronous operations... :/
A synchronous call would stop the Silverlight UI thread and possibly the executing environment, i.e. the browser. To prevent this, only asynchronous calls are allowed.
Of course this is something unusual at first, but in the long run it is actually helpful to decouple the view and service layer.
Silverlight does not support synchronous calls (which is what you're doing in your console app).
Update: http://forums.silverlight.net/forums/p/34531/104526.aspx "The main point is that it looks like synchronous behaviour was removed on account of not being supported by all browsers."

Categories

Resources