I have two projects, one is a set of WCF services (let's call P1) and the other is a standard web application (P2).
As a start, we have consumed P1 services in P2 as SOAP services and everything went fine. Later we noticed that in all of our project deployments, we are hosting both P1 & P2 on the same server. So we thought why should we keep it like this - meaning: Why should we serialize/de-serialize the request/response every time for every method when it is running in the same server. So we made a decision to use P1 as standard project library reference in P2.
We had to make a lot of modifications because the proxy class name changes and having to remove the client "close" method after each call. Now, we have a new deployment that will requires P1 to be on a different server than P2, which we can change, and we have to consume P1 again as WCF service - meaning tons of changes all over the P2 and ending by having the serialization overhead on all of other deployments!
The question is, is there any way to make such a dynamic reference to P1, so no coding is required regardless the deployment is on 1 or 2 servers?
It is possible to make a WCF service run local( project reference ) or as a service based on some key on the web.config. I did the following example but I didnt test it but I have done exactly similar thing before
Add key in the web config say serviceMode="local/service"
Then say you have wcf service interface
[ServiceContract]
public class ICalculator
{
[OperationContract]
int Add(int x, int y);
}
implementation
public class Calculator
{
public int Add(int x, y)
{
return x+y;
}
}
///Now in your web application
you will have
public LocalProxy:ICalculator //this will use direct instance of the Calculator Service
{
private ICalculator _calculator
public LocalProxy(ICalculator calculator)
{
_calculator =calculator;
}
public int Add(int x, int y)
{
return _calculator.Add(x,y);
}
}
public class RemoteProxy:ICalculator ///This will be real wcf proxy
{
public int Add (int x,int y)
{
var endpointAddress = new EndpointAddress(EndpointUrl);
ChannelFactory<ICalculator> factory = null;
ICalculator calculator ;
try
{
// Just picking a simple binding here to focus on other aspects
Binding binding = new BasicHttpBinding();
factory = new ChannelFactory<ICalculator>(binding);
calculator= factory.CreateChannel(endpointAddress);
if (calculator== null)
{
throw new CommunicationException(
String.Format("Unable to connect to service at {0}", endpointUrl));
}
int sum= calculator.Add(x,y);
((IClientChannel)calculator).Close();
calculator = null;
factory.Close();
factory = null;
return sum;
}
finally
{
if (calculator!= null) ((IClientChannel)calculator).Close();
if (factory != null) factory.Abort();
}
}
}
Now how you use it
ICalculator _calculatorProxy;
//get the web config key here, you may use strategy pattern to select between the two proxies
if(key=="local)
{
_calculator= new LocalProxy(new Calculator)
}
else
{
_calculator= new RemoteProxy();
}
//then
_calculator.Add(3,5);
Note: Define your interfaces and data contracts in a separate assembly so that you can share it with the web application that needs wcf run as a service.
All your components in P2 which consume services from P1 should only consume the service interface (i.e. IMyService, ISomeOtherService). They should not care whether it is a local instance or a proxy and neither should they close the connection.
The easiest (imho) to realize this is by using dependency injection through an IoC like Castle Windsor (it's the only one I'm vaguely familiar with but there are several others out there). The container will be responsible to provide instances of the service interfaces. You can provide different implementations and configure the container at runtime with the appropriate one (WCF service or local instance). The container will also be responsible for disposing of the service components once they are not required anymore (i.e. calling Close() on the WCF proxies and doing nothing for the others).
It's a big topic so I'd suggest you search the internet for some of the keywords - there is lot of material out there.
Related
In c# .Net Framework 4.5 (Visual Studio Ultimate 2012, Version 11.0.61219.00 Update 5), I'm trying to define a service variable at runtime for which webservice to use. Each webservice (there are many) are all defined the same except for the endpoint url but the credentials will not cross over to authenticate. The below condition is menial to simplify the issue at hand. The following code gives the error: Cannot implicitly convert type WebService2.Service to WebService1.Service.
What I've tried: calling functions to return the proper service but the parameters or assignment all require a specific type.
var service = new WebService1.Service();
service = new WebService2.Service();
I want to be able to use the variable service in the rest of the program without having to duplicate code everywhere for using the many web service references.
It seems like what you are looking to do, you would need a common interface between the two services so you could inject whichever service you wish to use.
public class WebService1 : IWebService {...service code}
public class WebService2 : IWebService{...service code}
public interface IWebService{...service methods you will be calling}
Then you could do the following.
IWebService service = new WebService1.Service();
service = new WebService2.Service();
Assuming that the different services share the same method names, you can create an interface that all of the services implement by using the interface
IMyService.cs
interface IMyService
{
void MyMethod(string filter);
}
MyWebServiceImplementation.cs
public class MyWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MySecondWebServiceImplementation.cs
public class MySecondWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MyImplemetationCode.cs
//Use different services from same variable
IMyService service = new MyWebServiceImplementation();
service.MyMethod("filter");
service = new MySecondWebServiceImplementation();
service.MyMethod("another filter");
This question already has answers here:
How do I pass values to the constructor on my wcf service?
(9 answers)
Closed 7 years ago.
I'm building server in C# and WCF. I have my Service and Contract with methods used by Client app. But the whole logic is separated in different class: BusinessLogic. I will inject all I need in BussinessLogic, like repositories/database providers or other data stored in memory. I use Poor man's dependency to build my BussinessLogic (it's my composition root). It's a console application, so BussinessLogic is creaed/resolved in Main(string[] args) method.
My problem is that WCF services are created with parameterless constructor, independent of the rest of the server. They are created every time, when used be the Client.
This is how my server looks like:
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(ServiceLayer), new Uri("net.tcp://localhost:8005"));
host.Open();
Console.WriteLine("Running... Press key to stop");
Console.ReadKey();
}
My services:
[ServiceContract]
public interface IServiceContract
{
[OperationContract]
...
}
public class ServiceLayer : IServiceContract
{
IBusinessLogic _businessLogic;
public ServiceLayer(IBusinessLogic businessLogic)
{
_businessLogic = businessLogic;
}
// Here, I would like to use IBusinessLogic
...
}
I found how to do this using IoC here (I didn't test it tho), but I'm looking for a best solution with Poor man's dependency, without any container or tool, just C# and .NET. If there isn't any solution as good as IoC or close to it, please comment.
If you model your application around commands and queries, it becomes very easy to create your WCF service as a thin maintenance free layer with just one service class.
When you have just one service class, you can use this service class itself as Composition Root or Humble Object and this means you don't need to inject any dependencies into the service class. This prevents you from having to do any integration into the WCF pipeline when it comes to dependency injection, at all!
When you apply these patterns, you can reduce your service to the following code:
[ServiceKnownType(nameof(GetKnownTypes)]
public class CommandService
{
[OperationContract, FaultContract(typeof(ValidationError))]
public void Execute(dynamic command) {
CreateCommandHandler(command.GetType()).Handle(command);
}
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider cap) {
yield return typeof(ShipOrder);
yield return typeof(CancelOrder);
yield return typeof(ConfirmOrder);
}
// Singletons
private static IUserContext userContext = new WcfUserContext();
private static dynamic CreateCommandHandler(Type commandType)
{
var context = new DbContext();
if (commandType == typeof(ShipOrder))
return Decorate(new ShipOrderHandler(context));
if (commandType == typeof(CancelOrder))
return Decorate(new CancelOrderHandler(context));
if (commandType == typeof(ConfirmOrder))
return Decorate(new ConfirmOrderHandler(context, userContext));
throw new ArgumentException("Unknown: " + commandType.FullName);
}
private static ICommandHandler<T> Decorate<T>(ICommandHandler<T> handler) {
return new WcfExceptionTranslatorCommandHandlerDecorator(
new LoggingCommandHandlerDecorator(
new Logger(),
new AuditTrailingCommandHandlerDecorator(
new PermissionCheckerCommandHandlerDecorator(
new ValidationCommandHandlerDecorator(
new TransactionCommandHandlerDecorator(
handler))))));
}
}
Poor man's DI is now called Pure DI.
You can use Pure DI to compose WCF applications. You need to do that in the Composition Root.
In WCF application, the Composition Root is a custom ServiceHostFactory.
This answer shows an example of how to do that.
You can customize the code in that answer to add more dependencies.
I'm looking for a way to cache objects in memory with a RESTful WCF service. The service is completely stateless and is hosted outside of an IIS. I want to implement the caching by myself, so memcached isn't an option.
Right now I'm thinking of hosting a separate stateful System.ServiceModel.ServiceHost that does all the caching. It'll communicate with the rest of the WCF methods through a separate port or by some other means. However I'm not sure if this is the ideal solution to my problem. Has anyone got any tips?
I understand your confusion between stateless service and a stateful host and how the two can interact.
In this code sample I demonstrate conceptually how an in-memory singleton (Caching mechanism, I refer to as CachingProvider henceforth) can be referenced by both the service class (the service instance more precisely during the lifecycle of the request) and the service host (in this case I chose it to be a Console Application)
I assume here, the service interface and class are both located within the console applicaiton project that hosts the service.
In this simple example, my primitive CachingProvider class basically acts as a counter of how many service calls are made to the GetData method, and the service host will poll the CachingProvider every 5 seconds to get the count of service calls made so far.
note: you can use the WCFTestClient utility to test this quickly.
Disclaimer: I by no means suggest that a complex Caching mechanism be implemented as simply as in this sample, this code is merely for demosntration purposes.
namespace ServiceHostConsole
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
string GetData(int value);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class TestService : ITestService
{
public TestService()
{
CachingProvider.CallCount++;
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
//For demonstration purposes only
static class CachingProvider
{
static CachingProvider()
{
//private static constructor can initialize
//static cacheable resources
_callCounter = 0; //Trivial example of initialization
}
private static int _callCounter;
public static int CallCount
{
set { _callCounter = value; }
get { return _callCounter; }
}
}
class Program
{
static void Main()
{
using (var host = new ServiceHost(typeof(TestService), new Uri("http://localhost/TestService")))
{
host.Open();
//Example how the ServiceHost can report on a persistent in-memory object that is being
//updated each time the service is called.
new Timer(state => Console.WriteLine("# of service calls: {0}", CachingProvider.CallCount), null, 0, 5000);
Console.Read();
host.Close();
}
}
}
}
I have a Client Application, a server and another client, lets call it third party. I have a callback interface as part of my contract that is implemented both by the third party and the client.
The third party will call a server operation(method) then the server will trigger a callback but instead of calling the callback of the third party, it will call the callback implementation of the client.
Yes, you can absolutely do that.
The easiest way is to implement your service as a PerSession service, and capture the callback context on initialization/construction. Typically I will add the service object (which really represents a connection at that point) to an internal core object.
Then, when you get in a message from a client, you can make a call to any of the service objects (not through the contract), and internally forward the data to the associated client.
This is a pretty minimal implementation of the concept, without exception handling, and some pretty bad design (static class BAD!). I haven't tested this, but the principles should hold even if I missed crossing an i or dotting a t. This example also forwards the calls to all clients, but selecting an individual client follows the same basic pattern.
Trying to do this with a singleton service will be more difficult, and a per-call service obviously won't work :)
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IContract
{
[OperationContract(IsOneWay = true)]
void SendTheData(string s);
}
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void ForwardTheData(string s);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.PerSession)]
public class ServiceConnection : IContract
{
private ICallback m_callback;
public ServiceConnection()
{
m_callback = OperationContext.Current.GetCallbackChannel<ICallback>();
ServiceCore.Add(this);
}
public void SendTheData(string s)
{
ServiceCore.DataArrived(s);
}
public void SendToClient(string s)
{
m_callback.ForwardTheData(s);
}
}
static public class ServiceCore
{
static private List<ServiceConnection> m_connections = new List<ServiceConnection>();
public static void DataArrived(string s)
{
foreach(ServiceConnection conn in m_connections)
{
conn.SendTheData(s);
}
}
public static void Add(ServiceConnection connection)
{
m_connections.Add(connection);
}
}
From a quick read of the Microsoft Duplex service documentation I don't think that will do what you want. There could be some other clever Kung Fu WCF way to do it but in my case I created a "PassThruService" for the server that implemented the same contract as the real service and sent any requests received onto the client.
This is a part of my code that explains the thrust of it.
private const int OPERATION_TIMEOUT = 5000;
private MyServiceClient m_client = new MyServiceClient();
public bool IsAlive() {
try {
logger.Debug("PassThruService IsAlive.");
bool isAlive = false;
ManualResetEvent isAliveMRE = new ManualResetEvent(false);
m_client.IsAliveComplete += (s, a) => { isAlive = a.Result; isAliveMRE.Set(); };
m_client.IsAliveAsync();
if (isAliveMRE.WaitOne(OPERATION_TIMEOUT)) {
return isAlive;
}
else {
throw new TimeoutException();
}
}
catch (Exception excp) {
logger.Error("Exception PassThruService IsAlive. " + excp.Message);
throw;
}
I don't fully see what you're really asking here.... but I'll try to give some tips anyway.
Relaying messages or routing is not very well supported in WCF in .NET 3.5 - the infrastructure is there, but it's still a lot of work to set it up manually.
The best intro I know into this topic for WCF in .NET 3.5 is a two-part article by Michele Leroux Bustamante on MSDN magazine:
Building a WCF Router, Part 1
Building a WCF Router, Part 2
Part 2 has a section on duplex routers - does that help you in your quest at all??
WCF in .NET 4.0 promises to bring additional support for routing - there will be a RoutingService base class which can be leveraged to write routing services, and it will allow for configurable, content- or metadata-based routing - whatever it is that you need.
.NET 4.0 is scheduled to be released sometime later this year (2009) - hopefully! So while this is still the future, it's looking rosy!
Marc
I think I found the solution..
Here's the link.
http://msdn.microsoft.com/en-us/magazine/cc163537.aspx
Try to look at figure 6. That's what I'm trying to achieve.
I am trying to migrate my .net remoting code to wcf but I'm finding it difficult. Can someone help me migrate this simple Remoting based program below to use WCF? The program implements a simple publisher/subscriber pattern where we have a single TemperatureProviderProgram that publishers to many TemperatureSubcriberPrograms that subcribe to the TemperatureProvider.
To run the programs:
Copy the TemperatureProviderProgram and TemperatureSubcriberProgram into seperate console application projects.
Copying to remaining classes and interfaces into a common Class Library project then add a reference to System.Runtime.Remoting library
Add a reference to the Class Library project from the console app projects.
Complie and run 1 TemperatureProviderProgram and multiple TemperatureSubcriberProgram.
Please note no IIS or xml should be used. Thanks in advance.
public interface ITemperatureProvider
{
void Subcribe(ObjRef temperatureSubcriber);
}
[Serializable]
public sealed class TemperatureProvider : MarshalByRefObject, ITemperatureProvider
{
private readonly List<ITemperatureSubcriber> _temperatureSubcribers = new List<ITemperatureSubcriber>();
private readonly Random randomTemperature = new Random();
public void Subcribe(ObjRef temperatureSubcriber)
{
ITemperatureSubcriber tempSubcriber = (ITemperatureSubcriber)RemotingServices.Unmarshal(temperatureSubcriber);
lock (_temperatureSubcribers)
{
_temperatureSubcribers.Add(tempSubcriber);
}
}
public void Start()
{
Console.WriteLine("TemperatureProvider started...");
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpServerChannel tcpChannel = new TcpServerChannel("TemperatureProviderChannel", 5001, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingServices.Marshal(this, "TemperatureProvider", typeof(ITemperatureProvider));
while (true)
{
double nextTemp = randomTemperature.NextDouble();
lock (_temperatureSubcribers)
{
foreach (var item in _temperatureSubcribers)
{
try
{
item.OnTemperature(nextTemp);
}
catch (SocketException)
{}
catch(RemotingException)
{}
}
}
Thread.Sleep(200);
}
}
}
public interface ITemperatureSubcriber
{
void OnTemperature(double temperature);
}
[Serializable]
public sealed class TemperatureSubcriber : MarshalByRefObject, ITemperatureSubcriber
{
private ObjRef _clientRef;
private readonly Random portGen = new Random();
public void OnTemperature(double temperature)
{
Console.WriteLine(temperature);
}
public override object InitializeLifetimeService()
{
return null;
}
public void Start()
{
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
int port = portGen.Next(1, 65535);
TcpServerChannel tcpChannel = new TcpServerChannel(string.Format("TemperatureSubcriber_{0}", Guid.NewGuid()), port, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
ITemperatureProvider p1 = (ITemperatureProvider)RemotingServices.Connect(typeof(ITemperatureProvider), "tcp://localhost:5001/TemperatureProvider");
_clientRef = RemotingServices.Marshal(this, string.Format("TemperatureSubcriber_{0}_{1}.rem", Environment.MachineName, Guid.NewGuid()));
p1.Subcribe(_clientRef);
}
}
public class TemperatureProviderProgram
{
static void Main(string[] args)
{
TemperatureProvider tp = new TemperatureProvider();
tp.Start();
}
}
public class TemperatureSubcriberProgram
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to start TemperatureSubcriber.");
Console.ReadLine();
TemperatureSubcriber ts = new TemperatureSubcriber();
ts.Start();
Console.ReadLine();
}
}
In WCF, with a "push" from the server you're really talking about duplex comms; the MarshalByRefObject is largely redundant here (AFAIK). The page here discusses various scenarios, including duplex/callbacks.
If the issue is xml (for some philosophical reason), then simply using NetDataContractSerializer rather than DataContractSerializer might help.
The other approach is to have the clients "pull" data periodically; this works well if you need to support basic http, etc.
What it sounds like you want to do is use WCF NetTcpBinding with Callbacks.
Take a look at this: http://www.codeproject.com/KB/WCF/publisher_subscriber.aspx
"Learning WCF" by Michele Bustamante is also very good. You can get Chpt1 for VS2008 at her website along with the code for the book. Chpt1 will explain/demo setting up connections and such. She also has downloadable sample code. One of the Samples is a DuplexPublishSubscribe.
You will need to modify your logic a bit. If you want to migrate this app to WCF. You will need to have clients pull data from the service at regular intervals.
You will also need a Windows service or application to host the WCF like the console you are using in the previous code.
Well I build real time systems so polling is not an option - I need to push data.
Also I am finding there is no WCF equivalent of System.Runtime.Remoting.ObjRef! This is an extremely useful type that encapsulates a service endpoint and can be serialise and passed around the network to other remoting service.
Think I’ll be sticking with good old remoting until the ObjRef equivalent is introduced.
Yes it is true, just one correction..
ObjRefs are created automatically when any MarshalByRefObject derived object is going outside the appdomain.
So in this case your ITemperatureProvider interface Subscribe method shoud take ITemperatureSubscriber instead of objref.
And then on client side just call p1.Subscribe(this) and the remoting layer will generate ObjRef from the object that will be serialized and sent. (sending b reference)