views:

69

answers:

1

So I currently have 2 WSDLs added as Service References in my solution. They look like this in my app.config file (I removed the "bindings" field, because it's uninteresting):

<system.serviceModel>
  <client>
    <endpoint address="http://localhost:8080/query-service/jse" binding="basicHttpBinding" bindingConfiguration="QueryBinding" contract="QueryService.Query" name="QueryPort" />
    <endpoint address="http://localhost:8080/dataimport-service/jse" binding="basicHttpBinding" bindingConfiguration="DataImportBinding" contract="DataService.DataImport" name="DataImportPort" />
  </client>   
</system.serviceModel>

When I utilize a WSDL, it looks something like this:

using (DataService.DataClient dClient = new DataService.DataClient())
{
  DataService.importTask impt = new DataService.importTask();
  impt.String_1 = "someData";
  DataService.importResponse imptr = dClient.importTask(impt);
}

In the "using" statement, when instantiating the DataClient object, I have 5 constructors available to me. In this scenario, I use the default constructor:

   new DataService.DataClient()

which uses the built-in Endpoint Address string, which I assume is pulled from app.config. But I want the user of the application to have the option to change this value.

1) What's the best/easiest way of programatically obtaining this string?

2) Then, once I've allowed the user to edit and test the value, where should I store it?

I'd prefer having it be stored in a place (like app.config or equivalent) so that there is no need for checking whether the value exists or not and whether I should be using an alternate constructor. (Looking to keep my code tight, ya know?)

Any ideas? Suggestions?

EDIT

Maybe I should ask about these Alternate constructors as well.

For example, one of them looks like this:

   new DataService.DataClient(string endPointConfigurationName, 
                              string remoteAddress)

What values could get passed for "endPointConfigurationName" and "remoteAddress"?

EDIT2

Answering my own questions here, the "endPointConfigurationName" appears to be the same as the "name" in the app.config XML and the "remoteAddress" is formatted the same as "endpoint address" in the app.config XML.

Also! The answer to my first question about getting the EndPointAddresses is the following:

ClientSection clSection =
   ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;

ChannelEndpointElementCollection endpointCollection =
   clSection.ElementInformation.Properties[string.Empty].Value as ChannelEndpointElementCollection;

Dictionary<string, string> nameAddressDictionary = 
   new Dictionary<string, string>();

foreach (ChannelEndpointElement endpointElement in endpointCollection)
{
   nameAddressDictionary.Add(endpointElement.Name, 
                             endpointElement.Address.ToString());
}

EDIT3

Ok, I think I've figured out the 2nd half (and thus, full solution) to my problem. I found this on another website and I modified it to meet my needs:

Configuration configuration; 
ServiceModelSectionGroup serviceModelSectionGroup;
ClientSection clientSection;

configuration = 
    ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
serviceModelSectionGroup = 
    ServiceModelSectionGroup.GetSectionGroup(configuration);
clientSection = serviceModelSectionGroup.Client;

foreach (ChannelEndpointElement endPt in clientSection.Endpoints)
{
  MessageBox.Show(endPt.Name + " = " + endPt.Address);
}
configuration.Save();

With this code, we have access to the clientSection.Endpoints and can access and change all the member properties, like "Address". And then when we're done changing them, we can do configuration.Save() and all the values get written out to a user file.

Now here's the catch. In debug mode, the "configuration.save()" does not appear to actually persist your values from execution to execution, but when running the application normal (outside of debug mode), the values persist. (Which is good.) So that's the only caveat.

EDIT4

There is another caveat. The changes made to the WSDLs do not take effect during runtime. The application needs to be restarted to re-read the user config file values into memory (apparently.)


The only other thing that I might be interested in is finding a way (once the values have been changed) to revert the values to their defaults. Sure, you can probably delete the user file, but that deletes all of the custom settings.

Any ideas?

EDIT5

I'm thinking Dependency Injection might be perfect here, but need to research it more...

A: 

If you're using Microsoft Add Web Reference to create your service reference, then I think you may have trouble changing the connection programmatically. Even if you did change the auto generated code, as soon as you did an Update Service Reference it'd be overwritten.

You're best bet is to scratch Microsoft's auto generated code and build your own WCF classes. It's not difficult, and offers lots of flexibility / scalability.

Here's an excellent article on this very subject.

As for storing the custom addresses, it would depend on your app whether it's a Silverlight, Windows or web app. My personal choice is the database.

Matt
I'll read that article again (my eyes started to glaze over about halfway down the article...) But I would disagree: It is *quite* difficult. Especially considering that I barely know what these WSDLs are supposed to be doing. And I may have up to 22 WSDLs that I will eventually have to integrate. "Add Service Reference" was wonderful magic. Limiting, for sure, but wonderful in that it got my project going quickly. (I'll give you a +1 anyway, as it's a good find. Thanks!)
Pretzel
Yes, I realize I sound like a lazy programmer. Aren't we all, to some extent? :-) I swear I'll take a few more shots at this, but it seems like I'm trying to get a degree in Civil Engineering and Architecture, just to build a shack in my backyard. Ya know?
Pretzel
@Pretzel - Good grief, 22 references! In that case there's an quick and dirty solution that I've used in the past. Try leveraging partial classes. The idea would be have a partial class for the auto generated ones so that you don't lose your code on an service reference update. Either way you're at a crossroads though. Either learn and dissect the Microsoft generated code, or write your own.
Matt
@Matt: -1 for misleading information. If he were using "Add Web Reference", then he should probably stop doing that. That's part of the old ASMX technology that Microsoft considers to be "legacy technology". If he had to use it, then he could simply set the `Url` property of the proxy instance. It's very easy.
John Saunders
To anyone reading this, I didn't use the answer that "Matt" gave, but rather the one he left in his comments. I used two solutions: In one app, I created/implemented Partial Classes. In the other app, I changed the values (per EDIT4 above) and then restarted the app so that the changes would take effect.
Pretzel