I am building an single application that uses WCF to call out to multiple external endpoints. All of the remote endpoints are identical except for the URI. I would like to treat them as a pool: add and remove endpoints through configuration and have the application understand what to do.
My original plan was to define one endoint in the app.config, then iterate over my list of endpoints and update client.Endpoint.Address on the fly to point to the right place. Unfortunately, that property is read-only, rendering that plan unworkable.
I'm a little bit stumped here. Any suggestions on how I might accomplish this?
How to: Create a Service Endpoint in Code shows you how to manage service endpoints in code rather than configuration.
Have you tried a separate name that is passed in to the client constructor?
<endpoint address="http://localhost:18000/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="BasicHttpBinding_IMyService" />
<endpoint address="http://localhost:18001/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Secondary" />
<endpoint address="http://localhost:18002/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Tertiary" />
Store the end point addresses in a DB table and use Jason's suggestion for creating end points in code. When a new endpoint shows up you just add another row to the table and force the service to re-query the endpoint table.
How to: Create a Service Endpoint in Code
http://msdn.microsoft.com/en-us/library/ms731080.aspx
Related
I want to use Slot Swapping on Azure for a WCF Service. I know that we can do the appSettings directly in Azure. I couldn't find an option to configure the system.serviceModel/client, but for slot swapping i need 3 endpoint configurations, one on each slot I have
<system.serviceModel>
<client>
<endpoint address="http://myservice-devslot.azurewebsites.net/ServiceName.svc" ... />
</client>
This would be the configuration for 1 slot, as it's shown in the address: dev-slot
Or is there an other approach to manage endpoints?
Ok, I configured the endpoint address through Code and added an EndPointAddress Key to the AppSettings. Now I can swap from TEST to INT etc by just do one click in Azure. Thanks everyone
wcfServiceClient.Endpoint.Address = new EndpointAddress(endPointAddress);
For editing config files depending on the destination environment you're going to deploy the application to, you'd usually use config transformations.
As you're looking to so using azure, have a look at this article by Brady Gaster as starting point. It describes the whole procedure quite detailed.
Has any one ever implemented a custom serializer in WCF ? The reason i want to replace the WCF default serializer with custom serializer is to call different services from the same wcf proxy client.I would be glad if some one can suggest a way to do this ?
I did something similar on a project I recently did.
However I did have 2 different WCF clients. How I "switched" was I then created a shared interface between the clients and then used a ServiceLocator to fetch the IClient.
Does this make sense?
If I understand the problem correctly you have an application that you want to talk to one of two services that use the same interface based on some criteria. The services have different configurations so you cannot reuse the same config.
To tackle this I would setup the two configurations in the application config, it could also be done in code if you wish.
<client>
<endpoint address="http://service1"
binding="basicHttpBinding"
bindingConfiguration="Service1Binding"
behaviorConfiguration="Service1Behavior"
contract="IServiceInterface, Service"
name="Service1"/>
<endpoint address="http://service2"
binding="basicHttpBinding"
bindingConfiguration="Service2Binding"
behaviorConfiguration="Service2Behavior"
contract="IServiceInterface, Service"
name="Service2"/>
</client>
In your code you then need some sort of conditional statement to determine which service you want to talk to. Once you have done this you can create a ChannelFactory for the required configuration.
string serviceName = FullMoon ? "Service1" : "Service2";
var channelFactory = new ChannelFactory<IServiceInterface>(serviceName);
var proxy = channelFactory.CreateChannel();
proxy.SomeServiceCall();
channelFactory.Close();
If you are using IoC to inject the proxy you will probably need to push this into some sort of factory. You can also look at optimizing this as creating the ChannelFactory is the expensive part, it is possible to create the Factory without specifying the configuration just the contract. You would then need to specify the binding and the endpoint when you create the channel.
I have a long-running service that gets data from one source, manipulates it, stores it in a database, etc.
I'd like to expose some methods on that service to other applications. Currently we do this via .NET Remoting but I'd like to move to WCF.
Unfortunately, I the endpoint I connect to is never the one I exposed via my long-running service. Below is a simple example:
[ServiceContract]
public interface ITestWcfService
{
[OperationContract]
CounterResult GetCurrentValue();
}
public class TestWcfService : ITestWcfService
{
private ITestWindowsService _service;
public TestWcfService() { /*NOTE: For discoverability*/ }
public TestWcfService(ITestWindowsService service)
{
_service = service;
}
public CounterResult GetCurrentValue()
{
return _service.GetCurrentValue();
}
}
public interface ITestWindowsService
{
CounterResult GetCurrentValue();
}
Then I have my actual Windows Service, which self-hosts the WCF service via the ServiceHost class.
public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
private static ServiceHost _wcfService;
public TestWindowsService()
{
InitializeComponent();
}
public void OnStart(string[] args)
{
//Create instance of WCF, passing in reference to this service instance
TestWcfService wcf = new TestWcfService(this);
_wcfService = new ServiceHost(wcf);
}
public CounterResult GetCurrentValue()
{
//Note: Some logic here
}
}
Now, this more-or-less works except that each time I make a call to the TestWcfServiceClient(), it uses the default constructor and creates a new instance of the Wcf Service and does not use the instance created by the windows service. This means that when I call GetCurrentValue() I get a null reference because the _service member hasn't been set.
I've looked around for solutions and found some citing ServiceHostFactory and ServiceHost and IInstanceProvider but each has seemed to be very, very complicated.
Any thoughts you could provide would be most appreciated.
EDIT: Here's my ServiceModel info
<system.serviceModel>
<services>
<service name="WcfService.TestWcfService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
WCF is VERY extensible, but in order to provide such extensibility it is also very complicated. In my opinion, more than it should be so if you want to use this implementation that's the way to go. YOu have to create a behavior that changes the service factory so you can use the custom constructor instead of the empty one.
However, I think there might be another alternative. Since both the service and the WCF share the same app domain they can share values through static objects.
I would move the logic that carries the value you want to expose to un underlying assembly (if you didn't already) and both the service and WCF service would see the same instance therefore you don't need to change all the WCF plumbing.
You are trying to put a square peg in a round hole.
WCF is explicitly designed to enable calling business logic independent of how it is hosted. You are trying to maintain the old remoting design that has your business logic in the host layer (in this case a Window's service). As a result you are asking to pass information back up to the host in a way that is possible in WCF but ugly and is generally avoided for many good reasons.
If you want a clean WCF design you will need to create abstraction layers and move your business logic out of the existing TestWindowsService class. Then the windows service creates the WCF service host, the WCF host creates the WCF service, and the WCF service is not dependent on the classes that host it.
Having said all that...
To actually answer your question:
Conceptually the code that you have written should work. Passing an object instance into the ServiceHost constructor is by far the easiest way to avoid the complexity of writing a custom IInstanceProvider. A couple of things to check:
When you pass a service instance into the ServiceHost constructor it needs to be marked as a singleton.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
Make sure that initialization is really working the way you think it is:
Put a guard on your TestService(ITestWindowsService) constructor that throws if service is null.
You have a comment on the default constructor for TestWcfService() that says "for discoverability". I would remove that constructor (at least while you are troubleshooting). A piece of code might be using that constructor to host a service instance you don't want. This is likely to cause your app to start throwing exceptions or compile errors that point out your real problem.
If you are still having problems: What does the Service Model section of your app.config look like?
Learning WCF (I know, late to the party)
I am working through Juval Lowy's Programming WCF book. I see that I can configure multiple endpoints (including URI's) for my service.
However, when I host these in IIS, only the location of the .svc file seems to matter. Is the multiple endpoints/addresses thing only applicable if you are self-hosting? Am I missing something about hosting services in IIS?
"only the location of the .svc ", you're heading to this because baseaddress are provided by IIS in case of web-hosting (IIS hosting) unless you're using CustomServiceHostFactory. Then whatever value you provide in address, are appended to baseaddress (.svc/..)
You needs to give several host name in IIS for the the same WCF and set several endpoints in the client section of web.config as:
<client>
<endpoint address="hostname1/myservice.svc" ... />
<endpoint address="hostname2/myservice.svc" ... />
<endpoint address="hostname3/myservice.svc" ... />
</client>
Then you can consume them as:
hostname1/myservice.svc
hostname2/myservice.svc
hostname3/myservice.svc
Is it possible to have one service with two behavior configurations? As you know it is possible to have one service and more than one endpoint where you can specify different binding configuration.
But I need to have, for the same service, different service behaviors.
If I try something like this:
<services>
<service name="Service.Service1" behaviorConfiguration="Behavior1">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
<service name="Service.Service1" behaviorConfiguration="Behavior2">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
</services>
... I got error "A child element named 'service' with same key already exists at the same configuration scope"
I know that I can create new class that inherits original service class but is there better solution?
Seems that you should register the same service class with another service name. Service behavior is a part of service configuration so if you want to use different behaviors you should configure different services. My question to you: if you will have one service with two behaviors, how wcf will decide to use this one or another?
Why you solution with inheritance is bad?
Quite intriguing question... I am not certain if what I am describing is possible but solution would be some thing like below:
Choose different name for service - there will be some scheme such as name="Service.Service1.Entry1"
Write custom ServiceHost (perhaps coupled with IInstanceProvider) that will ignore the last .Entry1 part and creates the service instance using Service.Service1 name.
Yet another way would be injecting dynamic type named "Service.Service1.Entry1" inherited from Service.Service1 when application is initializing. This part is very much possible - i.e. for every mentioned service, you would create n subtypes dynamically at app start-up so that you can use them as intended.