Having WCF service proxy configurable - c#

I am writing a basic WPF GUI to connect to a WCF service and consume an interface. So far I have connected to the test system by creating a service reference, putting in the URI for the test service I want to consume, it finds the interface and creates the proxy via service reference for me.
What I want this to do when you run the GUI app is for the user to be able to pick an environment - development, test or production and for the GUI to then connect to the appropriate WCF service depending on the environment selected.
How can I do this?

You can overwrite the Endpoint like this:
client.Endpoint.Address = new EndpointAddress(GetAddressForCurrentMode())
The other way you could to it, is to write a method, maybe an extension method, that accepts the service contract and the implementation class. Further more it either accepts a configuration name, or an endpoint:
public static TClient GetServiceClient<TClient, TContract>(string endpoint)
where TClient : ClientBase<TContract>
{
// Construct client
}
To construct the client, use one of BaseClient<T> overloads (from MSDN).
To then consume the client, just use the method above as normal:
using(var client = ServiceInterop.
GetServiceClient<MyClient, IMyContract>("http://foo.bar"))
{
// Consume client
}

Related

State inside self-hosted WCF service being lost with InstanceContextMode.Single

I am using WCF service and self hosting it as not everything is contained within the service itself (some external events are happening outside of the service):
WCF Service and I am self hosting it in a C# Console App. When WCF clients conncet they call the Login function, and I (try!) to store their callback via GetCallbackChannel
3rd party DLL which calls my console back via a delegate on a different thread from the library
On this console callback I then call in to the WCF service who pool which is then passed on to the WCF service who then broadcasts to all connected clients via a callback contract.
All is fine with the client connecting, calling Login, and I save the callback interface object.
However when I access the code from my service, i find it is an entirely new object and my _endPointMap is empty (despite me storing it in the Login method which is called by the client):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService, IEndpointNotifier
{
public readonly TwoWayDictionary<string, IClientCallback> _endpointMap = new TwoWayDictionary<string, IClientCallback>();
// called by WCF client when they click the login button - it works
public void Login(string username)
{
var callback = OperationContext
.Current
.GetCallbackChannel<IClientCallback>();
_endpointMap.AddOrUpdate(username, callback);
list.Add(username);
}
// called by the WCF self-host console app
public void IEndpointNotifier.Notify(string info, string username)
{
// at this point my list _endpointMap is empty despite
// having received a Login previously and adding to the
// list. so i am unable to call my clients back!!
_endPointMap.Count(); // is 0 at this point?!!
}
}
My main console app starts up the service fine also as below:
static void Main(string[] args)
{
var service = new Service();
var host = new ServiceHost(service);
// between the above line and the task below calling
// service.Notify I click a number of times on client
// which calls the Login method
Task.Run(() =>
{
for (var i = 0; i < 3; i++)
{
Thread.Sleep(10000);
// at this point, service seems like a new object?!
// any data saved in the list member will be lost,
// and will only see the single entry from time of
// construction
service.Notify("hi","bob");
}
});
Console.ReadLine();
}
Questions please
The object seems totally different to the one that was modified in a previous operation (on login from client) - is there any way to tell what service object I am actually looking at (equivalent to the old C++ days and looking at the address pointer for this)?
The singleton attribute seems to be ignored [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] Any ideas what I am doing wrong (why the internal list variable keeps getting reset)?
The WCF service cannot be self contained. How does one achieve communication between WCF self-hosted app and the WCF service according to best practice or is this abusing WCF and what is was designed for (when considering scopes etc)?
I set the breakpoint in the constructor with some dummy values. That breakpoint is only ever hit the first time when i construct it. When i go in to the object via the service.Notify method although the object seems new (members are empty) the constructor breakpoint is not hit - how so?
I have hosted the 3rd party app behind a static global member variable that I control. So I am responsible for all communication and state and cleanup between the 3rd party lib and the normal wcf calls. I am responsible for thread lifetimes for the 3rd party app. If I create them I have to close them. Holding references in my own lists.
It is like it is a separate app but they just happen to be in the same process space. All communication to and from the 3rd party app is controlled by me formally.
You will probably need a thread that looks for completed or abandoned 3rd party objects after usage to kill them your self outside of normal wcf msg processing.
This lets the wcf part be a normal threaded (thread pool) concept with no special declarations.
side note:
I would take out the loop and make it two lines in your simple model.
service.Notify("hi")
Console.ReadLine();
This will expose your object lifetime details instead hiding them for 3 seconds.
I found why the values were not being saved... my WCF client proxy was connecting to the VS WCF Service Host and not my host in the code!
I noticed this when I saw the WCF Service Host running in the service bar tray.
I disabled WCF Service Host starting up for the WCF .svc service by right clicking on the WCF Project -> Properties -> WCF Options -> unticked Start WCF Service Host when debugging another project in the same solution

Implement a WCF-Mock and the endpoint before implementing the real service

Background:
I have to extend an application which already uses WCF services with another WCF Service. One of these already existing services should call the new WCF service. Now the requirements are that the future service should be mocked and the connection between this two services should be tested (not a unit test) with this mock service before implementing the real service. The mock service should write the received parameters to a file.
Goal:
This means the endpoint in the existing WCF service is implemented and ready (except for some changes in the config).
My approaches:
Implement own mock service (Blog post) or use a mock framework (WCFMock) which mocks a already defined interface.
Problems:
The call of the mock service looks different and I have to change the code of the endpoint after the implementation of the real service.
My Question:
Is it possible to mock or fake a WCF service (without real web call) and implement the endpoint which will also work with the real WCF service after changing the config?
Yes. You will need to create a class that acts as an intermediary for the WCF service client calls and then either loads an actual client or your mock service depending on some value (probably a config value). This way, the dependencies in your code are handled such that all you need to do is change a flag in order to switch implementations.
The biggest constraint on this working is that the service interface must be available to the client to implement.
Basic idea is as follows:
public class ServiceFacade : IMyWCFService
{
private IMyWCFService _clientImplementation;
public ServiceFacade()
{
_clientImplementation = (Settings.Default.UseMockService == true) ? new MockWCFServiceClient() : new MyWcfServiceClient();
}
#region IMyWCFService implementation
public int MyServiceCall()
{
return _clientImplementation.MyServiceCall();
}
#endregion
}

Interacting with Host objects in WCF Service

I'm creating a game application with networking and I'm trying to utilise WCF. Ultimately it will be a peer to peer system but for development purposes I've split the application into core and player applications. This means that WCF services need to interact with the data on both the host and the client. So my question is how do I get a service to interact with the objects on the host application. If I set the InstanceContextMode of the ServiceBehaviour attribute to InstanceContextMode.Single then I can pass a class instance to the ServiceHost constructor and can then interact with Host objects, but how do I do this when I'm passing a class type to the ServiceHost constructor, which I must do if I'm using PerCall or PerSession InstanceContextMode.
All the simple examples for WCF services use things like calculators. With the Calculator example you can pass data from the client via the method parameters of the class/ interface, and you don't need to interact with any objects on the host. Am I using the wrong tool for the job?
Take a look at full duplex communications in WCF... You should be able to find a whole bunch of chat room examples (that's a good parallel - many clients maintaining state through a central server).
http://msdn.microsoft.com/en-us/library/ms731064.aspx
A duplex service contract is a message exchange pattern in which both
endpoints can send messages to the other independently. A duplex
service, therefore, can send messages back to the client endpoint,
providing event-like behavior. Duplex communication occurs when a
client connects to a service and provides the service with a channel
on which the service can send messages back to the client. Note that
the event-like behavior of duplex services only works within a
session.
EDIT It looks like the question has more to do with how to access shared server state...
There are a number of ways to do this. One way to do this would be to create a singleton instance of a class on the server side that manages shared state:
public class GameState
{
public static readonly GameState Instance = new GameState()
private GameState()
{
}
public PlayerPosition[] GetPlayerPositions()
{
}
}
Then, in a service that is implemented as PerCall:
public class MyGameService : IGameService
{
public PlayerPosition[] GetPlayerPositions()
{
return GameState.Instance.GetPlayerPositions();
}
}

Call The Same WCF Service From Multiples Hosted Servers

I am a little consused with how to acomplish this task. The question is, How can I Call a WCF Services from Multiples Hosted Servers. The WCF is the same for all the Hosted Apps. Same Contract, Same Binding Type, Etc. I am trying to call it in this way because I will host the services in multiples Servers and I need the service to do the same in all of them. I have to call it from one client. VS 2010, .Net Framework 4.0., C#.
Thanks,
It depends how you plan to create service proxy in the client application. If you want to add service reference it is enough to add it from one server and then create separate endpoint configuration for other servers - all endpoints configurations will exactly same except the address (you can do the same in code). When you call services you will create proxy instance for each server and you will pass name of the endpoint (defined in configuration) for each server like:
foreach(var endpointName in myStoredEndpointNames)
{
var proxy = new MyServiceProxy(endpointName);
proxy.CallSomeOperation();
}
Another approach is not using add service reference. In such case you must share contracts between server and client application and you can use ChannelFactory. This class is factory for client proxies which are created by calling CreateChannel. You can pass endpoint configuration name, endpoint address or binding and endpoint address when calling this method.
I use a function like this:
public static MyWcfClientType GetWcFClient(string hostName)
{
MyWcfClientType client = new MyWcfClientType();
// Build a new URI object using the given hostname
UriBuilder uriBld = new UriBuilder(client.Endpoint.Address.Uri);
uriBld.Host = hostName;
// Set a new endpoint address into the client
client.Endpoint.Address = new EndpointAddress(uriBld.ToString());
return client;
}
Of course use your own type for the "MyWcfClientType"

WCF: Using Duplex for notifications across multiple instances of the same WCF service

What is the best possible way to share a single instance of a WCF Service (the SoapClient class) across multiple instances of an application (WPF)?
I need to do this because I need to enable duplex communications with callbacks, so i need to "register the application" to the the service so that other users using the application will get notified whenever a new user logs in.
Btw the below is striked out because I have confirmed that for the notifications to work, the registrants need to register to the same wcf service instance...thus now I need a way to share this instance
I am currently developing an application and I need some way to inform the users that are currently using the application whenever someone logs in the application.
I have tried using the WCF Duplex thing, but and I can't get it to work...and I think the reason behind it is because notifications and subscriptions need to occur to the same instance of the WCF Service.
But since this application will be deployed on multiple users' pcs, I cannot share only one instance of this wcf service eh? (or can I ?)
Is there a way to share a common instance of a wcf service (the SoapClient) for all the users? Or am I going about this the wrong way?
Currently I'm accessing the WCF Service through a class library via a public property that sends a new isntance of the wcf service every time it is accessed, and I think that that is the reason on why the notifications are not working on multiple instances of the application.
The following are the methods (in the class library) that the client application (a wpf app) uses to gain access to the service methods:
public static MusicRepo_DBAccess_ServiceClient GetService(object instanceContext)
{
return new MusicRepo_DBAccess_ServiceClient(new InstanceContext(instanceContext), dualBinding, endpointAddress);
}
public static MusicRepo_DBAccess_ServiceClient GetService()
{
return new MusicRepo_DBAccess_ServiceClient(new InstanceContext(new WSGateway()), dualBinding, endpointAddress);
}
In the main application window, I am then getting a new instance from the above overloaded method passing in this as the instanceContext parameter and the Open it to wait for the notifications but I am never notified when another user logs in from another instance of the application.
This is how I am notifying the registrars (excerpt) in the service login method:
if (!_callbackList.Contains(newUser))
{
_callbackList.Add(newUser);
}
_callbackList.ForEach(c => c.NotifyNewUserOnline(loggedInUser));
The solution was simple. All I needed was to change InstanceContextMode to Single:
[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single)]

Categories