Reuse WCF contract interface, but retain use of declarative configuration - c#

We've used the solution in this old topic ("WCF Service Reference generates its own contract interface, won't reuse mine"), but that only solves the problem of reusing interfaces. What we would like to do, if possible, is to also retain the use of config files to setup and configure various options on WCF client side using all the bells and whistles of <system.serviceModel> node.
The approach that was given forces us to do all that in code, and that already proved to be a problem at one point (we had to change a binding configuration parameter which forced us to go through an entire corporate change request approval process to alter two lines in the code base, which is a huge hassle compared to a request to change config file).
Is there a solution that combines these two worlds?

Lets say you have IService as your service contract and it is shared between the client and the server.
Then in client code you would have something like this:
ChannelFactory<IService> factory = new ChannelFactory<IService>("ServiceClient");
var channel = factory.CreateChannel();
var result = channel.GetData(1);
In Client app.cofnig you would have a section that looks like this:
<system.serviceModel>
<client>
<endpoint name="ServiceClient" address="http://localhost:51377/service.svc" binding="basicHttpBinding"
contract="Common.IService"/>
</client>
</system.serviceModel>
Briefly explained ChannelFactory creates Channel to access IService service using ServiceClient endpoint configuration in app.config.
You can expand serviceModel configuration as you wish. Just add additional code to properly close channel once operation is complete.

What exactly is it that you're trying to achieve? Seems like you're trying to reuse contracts, but have SVCUTIL/VS generate the ClientBase<T>-derived class and modify the .config file?
If so, I don't think that's a supported scenario, really. Honestly, if you need to reuse your service contract interfaces, you might as well implement the ClientBase<T>-based proxy class by hand. It's only a little bit of additional work, and will make your life easier in the long run.
There isn't a supported option in SVCUTIL/VS to only import the binding configuration rather than the entire thing, though, so you'd likely need to write your config file by hand as well (or copy it from a manual run of SVCUTIL).

Related

WCF: Is configuration in App.config better than in hard-coded in custom Proxy class?

first of all this is not duplicate. I have a little bit different question.
Is it good practice to get rid of WCF's config in App.config file in the client (or clients in case of cross-platform project) and replace it with injected Proxy class (from different dll, shared for all clients)?
I'm just starting so my config file is not big, but here is an example:
App.config (WCF part):
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:8002/MyService"
binding="netTcpBinding"
contract="CallbackExample.Client.IMyService" />
</client>
</system.serviceModel>
I must have this code copy and pasted into every client I made. Working with Xamarin I can have many clients written in C# in single VS solution. So I though, why not just get rid of system.serviceModel section and do that:
MyServiceProxy.cs:
public class MyServiceProxy : ClientBase<IMyService>, IMyService
{
public MyServiceProxy()
: base(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8002/MyService"))
{
}
public int JustAMethod()
{
return Channel.JustAMethod();
}
}
This way, I will have my configuration in single place.
So, my question is: Is it considered as a good practice? Is there a better way? I'm not sure, cause WCF is all about flexibility and easy config through App.config flie.
If there is no need for additional configuration, I always go for pure code solutions.
Back in the day WCF was slightly more complex to configure, via app.conf. With the ServiceHost you can even configure a WCF service in pure code.
The same applies to a WCF client imo; if you don't have the need to configure it via a config file for your users: I'd say go for the pure code solution.
Here another discussion of the same topic. (kind of the same reasoning, the question remains; do you need the configuration flexibility).
One potential downside to doing everything in code is that you lose the flexibility to configure not just the endpoint, but also the binding, without recompiling and redeploying. The binding includes some important network-related attributes (timeouts, transport protection levels, authorization schemes, etc) that you may want to tweak depending on the environment in which some of your client programs can run.
Note that you don't necessarily have to have a separate *.exe.config file for every client application. You can have a common .config file that each application can load explicitly. See ConfigurationManager.OpenMappedExeConfiguration

Consuming web service in class library

Scenario:
I am consuming a web service in my class library project and it generates a binding name and end point in app.config. If I reference the class library in my UI project, I also have to include the same configuration in web.config. My problem is I don't want to include this configuration in web.config because of the dependency. I want to use assembly as it own with out any dependency.
My solution approach:
When I create the instance of proxy class in the class library project it shows me constructor to pass binding and endpoint.
Example
wsProxy proxyClass = new wsProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.Endpoint endpoint)
I was wondering if I can pass the same binding and endpoint that I have in app.config so that I don't have to include either in app.config and web.config.
Yes, you can create these classes without having matching configuration in the main .config file. Where you get that configuration is up to you; it could be App.config, a YML configuration file, a database, etc. As long as your code satisfies the constructor requirements for the classes you're instantiating, you'll be fine.
With WCF, everything defined in your configuration file can be done programmatically.
You just need to create the objects needed to instantiate your client. Depending on the WCF features you want your application to be leveraging, you'll need classes like EndpointAddress, AddressHeaderCollection, Uri, EndpointIdentity (DnsEndpointIdentity or SpnEndpointIdentity), Binding (WSHttpBinding, NetTcpBinding etc.). And you might want to have these objects populated from a decoupled, centralized configuration store such as a database.

How to use custom serialization WCF?

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.

WCF and moving the proxy code to a DLL. Is it possible?

it looks like I am not able to succesfully move my WCF proxy code into a separate DLL (as opposed to an EXE as I can see in all the examples I have run into).
The reason I am trying to do this is that I would like my proxy code to be invoked by different clients (possibly unmanaged code), which might not know anything about WCF but just need to access to the services (through a Facade exposed by the proxy maybe?).
Whenever I move the following code that creates a new proxy to a different VS project within the same solution, I get the dreaded "Could not find default endpoint element that references contract 'localhost.IRemoteCommandService' in the ServiceModel client configuration section" exception.
localhost.RemoteCommandServiceClient proxy =
new localhost.RemoteCommandServiceClient();
The same code works smoothly whenever used within a Main method in the same project where the proxy code is (auto-generated from Visual Studio).
Any idea? I hope that the client code of my proxy does not need to have the service model XML configuration as the proxy, because that would defeat the purpose I am moving the WCF proxy code into a DLL in the first place.
Thanks,
Stefano
The endpoints are indeed normally specified in the configuration file. You must look at the serviceModel data in the config file, and copy it into your calling app.config - or you need to use the more verbose way of creating the proxies in your code (i.e. specifying the address, binding, configuration etc through code to the constructors).
If you don't want to have to endpoint configuration on the client, you'll have to embed it into your proxy dll by specifying everything in code.
Another option would be to use a dynamic proxy, like this one, which would allow you to not have the serviceModel in your client apps.

SOAP web service: many servers, one interface

I have a scenario in which I'm going to need an arbitrary number of servers to provide the same SOAP web service. I would like to generate one set of proxy classes and be able to supply them with a location to point them at the different servers at runtime. Unfortunately, it looks as though the wsdl:port node (child of wsdl:service) requires the address of a specific server to be hardcoded. It appears that due to this the URL will be baked into my proxy classes. I know that I could potentially modify this by hand-editing the generated proxy classes, or modifying the code generation, but I'd really prefer not to resort to that. I feel like there's got to be a better way to solve this problem. I just want to decouple the interface definition from the location that the service will be residing at. I'm using VS2008 and C#.NET if that's of any help though best would be a language-agnostic (SOAP or WSDL specific) general solution to this problem.
Why don't you load balance the web servers and then create a DNS entry for the load balanced IP address....essentially creating a web farm. This will allow you to reference the hostname rather than the static IP addresses and if you ever need to change the IP address of the load balancer or the web servers it is a one time change. Plus you then have redundancy and performance control.
If you're using a WebReference (pre-WCF) to get to the web service, you can simply set the Url property on the web service proxy class after you create it.
For WCF, you can provide a different endpoint address to the proxy class constructor, rather than using the default (among other possible solutions).
No, in .NET you can change the URL at runtime.
Service svc = new Service ();
svc.url = "Value read from config. file or some such"
output = svc.method (input);
When you add a web reference to your project, it places the address of the web service into the .config file of your application / web application. You can then simply change this setting in the config file to point to a different web service location, assuming of course that the services are identical.
The easiest solution would be to use a software load balancer such as HAProxy. At more cost, you could use a hardware solution such as Big-IP.
Here's a hint on how to decide the URL of WSDL. I´m just changing the port but it´s of course possible to make it more advanced.
public class PortChangeReflector : SoapExtensionReflector
{
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
SoapAddressBinding binding = extension as SoapAddressBinding;
if (binding != null && !binding.Location.Contains("8092"))
{
binding.Location = binding.Location.Replace("92", "8092");
}
}
}
}
}
}
Put that in your Add_Code and add the following reference to your web.config.
<webServices>
<soapExtensionReflectorTypes>
<add type="Dev.PortChangeReflector,App_Code"/>
</soapExtensionReflectorTypes>
</webServices>
I hope you can get new ideas of this.
Client proxies have URL property you can set at runtime. To make it simpler, wsdl.exe utility has /appsettingurlkey key. When you generate a client proxy, it's constructor will check the key in appSettings and set the service URL accordingly. I believe WCF has this feature as well.
However, I would agree with #Matt and suggest you consider load balancing as the best solution in the long run.
Is this for scaling (each server provides the same data) or
for same API different data on each server?
For 2, then you can do as above, just change the service URL in code.
For 1, you could use round-robin DNS (e.g. you see multiple servers with at the command line type nslookup www.google.com).

Categories

Resources