Possible ways of injecting a wcf client with structuremap - c#

I would like to use structuremap to inject a wcf client but I also would like that this client reads the endpoint and binding configurations from the config.
I tried the following:
For<IServiceClient>().LifecycleIs(new UniquePerRequestLifecycle()).Use<ServiceClient>().
Ctor<string>("endpointConfigurationName").Is("WsHttpBinding_IService");
But this will result in the error:
StructureMap Exception Code: 205\nMissing requested Instance property \"remoteAddress\" for InstanceKey \"e50e036b-9d71-47de-8ac2-d53a641e9be8\"
When I pass the remoteAddress it work's like expected:
For<IServiceClient>().LifecycleIs(new UniquePerRequestLifecycle()).Use<ServiceClient>()
.Ctor<string>("endpointConfigurationName").Is("WsHttpBinding_IService")
.Ctor<string>("remoteAddress").Is("https://myurl/Service.svc");
I don't understand why the first constructor overload does not read the endpoint address from the config?
The config looks like this:
>
<client>
<endpoint address="https://myurl/Service.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService" contract="IService" name="WsHttpBinding_IService" />
</client>

The first overload does probably read the endpoint address, but StructureMap never calls this first overload, but always calls the most greedy constructor. Prefer using the Use method and supply a factory delegate:
For<IService>()
.LifecycleIs(new UniquePerRequestLifecycle())
.Use(() => new ServiceClient("WsHttpBinding_IService"))
This forces the use of the right constructor for this generated class. Perhaps it's even better to hide that class behind a proxy. This way to can hide the annoying quirks of WCF from your application. And for types that you create yourself, prevent having multiple constructors.

Related

Pass a valid endpoint name to the service client constructor

I try to use web service for weather
http://www.webservicex.com/globalweather.asmx?WSDL
I make console application and try to use this service. First of all I add reference and name the reference WeatherService and write below code
Console.WriteLine("Now we get weather, please wait .......");
WeatherService.GlobalWeatherSoapClient w = new WeatherService.GlobalWeatherSoapClient();
Console.WriteLine(w.GetWeather("Lahore","Pakistan"));
But it gives me a exception
Additional information: An endpoint configuration section for contract 'WeatherService.GlobalWeatherSoap' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.
I am learning web services and don't know why this happens. Any one help me on this is great favor. Advance thanks.
Open your app.config, find needed then pass it's name to GlobalWeatherSoapClient(here):
in your app.config should be setting like this:
<endpoint address="http://www.webservicex.com/globalweather.asmx"
binding="basicHttpBinding" bindingConfiguration="GlobalWeatherSoap"
contract="WeatherService.GlobalWeatherSoap" name="GlobalWeatherSoap" />
get name and pass it to client:
WeatherService.GlobalWeatherSoapClient w = new WeatherService.GlobalWeatherSoapClient("GlobalWeatherSoap");

Accessing endpoint configuration from the contract

I'm using a ChannelFactory inside a PCL to consume a WCF service. My config looks something like this:
<client>
<endpoint
address="https://www.site.com/ProductService.svc"
binding="customBinding"
contract="Interface.IProductService"
...
And the code to consume it looks like this:
Binding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
ChannelFactory<Interface.IProductService> cf = new
ChannelFactory<Interface.IProductService>();
Interface.IProductService tc = cf.CreateChannel();
tc.GetProduct(1);
The problem that I have is that I am being asked to provide an endpoint name in nthe ChannelFactory constructor. Is it possible to have the ChannelFactory infer the correct endpoint from the contract alone?
Unless I'm misunderstanding your question, no. The endpoint is the combination of the ABC, not just the contract, and you might have different endpoints for different protocols. But, unless there is some other complicating factor you haven't named, it's pretty trivial to give the endpoint the name of the contract, and just pull it by name:
<client>
<endpoint name="IProductService"
address="https://www.site.com/ProductService.svc"
binding="customBinding"
contract="Interface.IProductService"
...
then:
Binding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
string typeName = typeof(Interface.IProductService).Name;
ChannelFactory<Interface.IProductService> cf = new
ChannelFactory<Interface.IProductService>(typeName);
Interface.IProductService tc = cf.CreateChannel();
tc.GetProduct(1);
Of course if you're doing this for lots of services, it's not practical. But if you're doing it in the same systematic way, I've found it useful to derive those interfaces from a base Interface, and handle the whole ChannelFactory management problem as an intermediary ChannelFactory<T> where T : IMyBaseContractInterface.

IIS hosting for WCF service with 2 contracts or hosting 2 services with dependencies

I'm developing a WCF service that has a contract called MyApp.IOperationService.
<service name="MyApp.OperationService">
<endpoint address="OperationService" binding="basicHttpBinding" contract="MyApp.IOperationService" />
</service>
For the service behaviour I used InstanceContextMode = InstanceContextMode.Single and ConcurrencyMode = ConcurrencyMode.Multiple because the application uses a shared physical resource.
I needed an administrative interface for this service and first I added a new contract within the same service. This approach didn't appeal to me because the administrative contract was exposed, through the metadata, to the clients using the operation contract.
Then I opted for creating another service altogether.
<service name="MyApp.AdminService">
<endpoint address="Admin" binding="netTcpBinding" contract="MyApp.IAdminService" />
</service>
This service has one operation, called Login, that propagates the pincode to the OperationService object.
namespace MyApp
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]
public class AdminService : IAdmin
{
MyApp.OperationService objOperationService = null;
public AdminService(MyApp.OperationService objOperationService)
{
m_objOperationService = objOperationService;
}
public void Login(string pincode)
{
m_objOperationService.Login(pincode);
}
}
}
In a self-hosting environment I create a MyApp.OperationService object, then pass this object to the constructor of MyApp.AdminService. For IIS hosting, I discovered that I need to use WCF extensibility points and implement an IInstanceProvider, then use a ServiceHostFactory.
At this point I stopped and wondered if this will work at all, given that my AdminService expects an already created MyApp.OperationService that IIS controls, and it already seems awfully complicated for my humble purpose.
The question is if this (administrative contract/interface for an existing service that is not exposed through the metadata) can be achieved in another way?
Thank you.
I couldn't find a way to solve the problem, except using WCF extensibility points. I used Microsoft.Practices.Unity to manage the services through IoC, then used the Factory property in the .svc file.

Could not find endpoint element with name and contract

I have added reference to a WCF service that has two end points. On adding the service the following get added to the Config file:
<client>
<endpoint name="ABCServiceV1" address="http://staging.ABCwebservices.com/ABC/Service.svc"
binding="basicHttpBinding" bindingConfiguration="ABCServiceV1"
contract="ABCService.IService" />
<endpoint name="ABCServiceV2" address="http://staging.ABCwebservices.com/ABC/Service.svc/20"
binding="basicHttpBinding" bindingConfiguration="ABCServiceV2"
contract="ABCService.IService1" />
</client>
The code to create the client is as as below:
ABCService.ServiceClient ABCClient = new ServiceClient("ABCServiceV2");
However, I am getting an runtime error - "Could not find endpoint element with name 'ABCServiceV2' and contract 'ABCService.IService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element."
if i used ABCService.ServiceClient ABCClient = new ServiceClient("ABCServiceV1"); then everything works fine. But when using ABCServiceV2 it is trying to look for Contract - ABCService.IService - when it should be looking for - ABCService.IService1.
How do i make it look for the correct contract?
If you added a second reference to a different service (ABCServiceV2) then I believe this will have generated a second service class for ABCServiceV2. The two classes will implement separate contracts (ABCService.IService and ABCService.IService1) so you won't be able to interchange the endpoints.
I believe you should be able to initialise your two service endpoints like so:
ABCService.ServiceClient ABCClient = new ServiceClient("ABCServiceV1");
ABCService.Service1Client ABCClient1 = new Service1Client("ABCServiceV2");
Even though this post is old and answered, the answer didn't help in my case.
My problem was I generated the service client with the svcutil.exe tool, but didn't specify any namespace at all; and so the contract namespace name was generated as the target namespace of the schema document by default, yes total mess.
On the other hand I was trying to use the config file generated when a service reference is added to the project. The contract namespace in this file is ServiceReference1 (by default) or any other name you want, perfect storm! But all I had to do was to remove the namespace part from the FQN from the <endpoint>'s contract attribute, and the contract became visible to the CLR.
Hope this help others

How to make your Service-Reference proxy URL dynamic?

I have a web reference to web-service:
using (var client = new GetTemplateParamSoapClient("GetTemplateParamSoap"))
{
TemplateParamsKeyValue[] responsArray = client.GetTemplatesParamsPerId(
CtId, tempalteIds.ToArray());
foreach (var pair in responsArray)
{
string value = FetchTemplateValue(pair.Key, pair.Value);
TemplateComponentsData.Add(pair.Key, value);
}
}
Tried to change a web-reference url from c# code: as advice here:
1) http://www.codeproject.com/KB/XML/wsdldynamicurl.aspx
2) How to call a web service with a configurable URL
3) http://aspalliance.com/283_Setting_Web_Service_References_Dynamically
But I get symbol is missing when trying to do:
client.Url
In addition I couldn't find a property of "Url_behavior"
It sounds like you've already added the service reference, but here's a walkthrough on adding, updating and removing service references.
Once you've got one of those in your project, you can alter the endpoint URI with one of the constructor overloads, as John Saunders said above. To do this, you'll need to know the name of the endpoint in your config file. For instance, after you add your service you might have elements like this in your config file:
<endpoint address="http://bleh.com/services/servicename.asmx"
binding="basicHttpBinding" bindingConfiguration="ServiceNameSoap"
contract="ServiceReference1.ServiceNameSoap" name="ServiceNameSoap" />
Given that endpoint, you can change the address at runtime by using the following overload:
var proxy = new ServiceReference1.ServiceNameSoapClient("ServiceNameSoap",
"http://new-address.com/services/servicename.asmx");
You can also do it after construction, but that becomes a little bit harder. If you need to do so, see the documentation on the Endpoint property and the associated type ServiceEndpoint.

Categories

Resources