Best way to manage multiple Service References in .NET - asp.net

I have a C# ASP.NET project with 15 WCF/ASMX Service References. Each service is deployed to three different servers; test, staging and live.
Often we need to change the URLs of these service references to different servers, to be able to debug using the correct service with the correct implementation and data.
When managing these Service References I'm having a hard time keeping the URL in sync. When creating a Service Reference FooService it stores the URL in three seperate files:
FooService.disco
configuration.svcinfo
Reference.svcmap
Along with creating an endpoint node with the URL in the Web.config.
If I change the endpoint URL in the Web.config and rebuild the project, it doesn't update the URL in the other files, so it's out of sync. So when I right-click the FooService and click Update Service Reference it doesn't use the URL stored in the Web.config, it uses the URL in the other files.
So the only way is to right-click the FooService and click on Configure Service Reference and enter the new URL. But that doesn't always work, because sometimes it creates a new node in Web.config named FooService1, so I get an error when running my application saying that there are two instances of the same endpoints.
So often I need to skim through the Web.config and delete duplicates of endpoints, which is very frustrating.
What is the best way to manage multiple WCF service references when changing the URL to the service often?

First an overview
The way I handle it is to not add the service reference via Visual Studio. What I have is each service has it's own Proxy project in the solution, to proxy is created using a simple one line batch file. Each of these is then included in the website(s) as a "vanilla" reference. The end point is configured manually in the web config. I have three deployment options: Debug (local), Staging and Release. At the web.config level the different addresses are handled by web.config transformations . The proxy project files are configured so that the correct end point address is used depending on the solution configuration. However it is important to note that web.config transformations only apply on publishing the solution.
In pre-VS2010 I had 3 variations of the web.config files which would overwrite the active web.config; however overwriting the web.config in this way always felt "risky" to me. In this case I think that using transforms for publish will still work, but in the actual web.config file have block of connections that you can comment in and out on those occasions when you want to debug the staging or development servers.
I only have 2 services, so my set up was pretty easy, with 15 there will be a fair bit of work involved to set up, but it will save you head aches in the long run.
Implementation
Back Up Everything First!!
Also keep handy a copy of the existing web.config to help with configuring the end points later on.
Also note that the batch files won't work if your solution is in a path with a space in its name, e.g. the default location VS puts its' projects. All my projects are in the following structure C:\Source\vs2008\, C:\Source\vs2010\ etc. I'll see if I can find a better solution for this.
0 Run VisualStudio as an administrator
Right click Visual Studio from the start menu and select "Run as Administrator". We need to do this as VS will be writing files.
1 Delete Existing service references
You shouldn't need any help on this one.
2 Add Proxy Projects
Doing this now means you only need configure the solution for test|staging|live once.
From the File menu select "Add" then "New Project" and from unser the "Visual C#" tmplates select "Class Library" and name it something sensible. I'll be using FooService.proxy for this example. Rename the class file, I'll be using FooService_proxy.cs in this example.
Add the following references to the project:
System.Runtime.Serialization
System.ServiceModel
Add one project for each service. We will comeback and update these projects later.
3 Configure The Solution to handle test|staging|live
I'm assuming you use test when developing the asp.net website on your local machine.
Open the "Configuration Manager" by selecting it in the Build Configuration dropdown menu.
Under the "Active Solution Configuration" dropdown select "New"
For the Name I'd suggest "Staging" and check the "Create new project configurations" check box.
In the Solution Explorer, right click on Web.Config and select "Add config transforms". This will add a new file for the staging web.config transformation. Click the expander arrow and you will see three sub files: Web.Debug.Config, Web.Release.Config, Web.Staging Config.
4 Set Up Proxies
Add a batch file to each proxy project by Clicking on the project in the solution explorer and selecting "Add > New Item". Use a text file and name it "CreateProxy.bat.
Insert the following into the new file and save:
:: ============================================================================================
:: Create the proxy file from the service wsdl
:: Input parameters
:: SDK Path The location of svcutil.exe
:: WSDL File Arg1 (%1)
:: Output Proxy .CS file Arg2 (%2)
::
:: Called by the build process of the BeforeBuild target to re-gen the proxy code.
:: Make sure to change FooService.proxy
:: ============================================================================================
svcutil %1 /ct:System.Collections.Generic.List`1 /serializer:DataContractSerializer /tcv:Version35 /n:*,FooService.Proxy /out:%2
Now right click on the proxy project and click "Unload Project", saving if prompted. This will enable us to get in and modify the project file. Right Click the now greyed out proxy project name and select "Edit".
Add the following just befor the closing </project> tag. Note you may need to change the
path SDKPath depending on your location of svcutil. Also make sure to name FooService_proxy.cs whatever you named the proxy file.
<PropertyGroup>
<!-- These properties are used by the svcutil batch file task in the BeforeBuild Target to regen the proxy code -->
<SDKPath Condition="'$(SDKPath)'==''">C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin</SDKPath>
<WSDLPath Condition="'$(WSDLPath)'=='' and '$(Configuration)' == 'Debug'">http://[Path to TEST Server Service]</WSDLPath>
<WSDLPath Condition="'$(WSDLPath)'=='' and '$(Configuration)' == 'Staging'">http://[Path to STAGING server Service]</WSDLPath>
<WSDLPath Condition="'$(WSDLPath)'=='' and '$(Configuration)' == 'Release'">http://[Path to LIVE Server Service]</WSDLPath>
<SkipProxyRegen Condition="'$(SkipProxyRegen)'==''">false</SkipProxyRegen>
</PropertyGroup>
<Target Name="BeforeBuild">
<Message Importance="normal" Text="Rebuilding the proxy code from batch file '$(ProjectDir)CreateProxy.bat'" Condition="'$(SkipProxyRegen)'=='false'" />
<Exec Command="$(ProjectDir)CreateProxy.bat $(WSDLPath) $(ProjectDir)FooService_proxy.cs" WorkingDirectory="$(SDKPath)" Condition="'$(SkipProxyRegen)'=='false'" />
</Target>
Save the changes and then right click on the greyed out project name and select "Reload Project".
Right click on the project and select build, make sure that your proxy file is now populated.
Set each proxy project so that it always build into only its' \bin directory, e.g. not bin\debug etc. Right click on the proxy project and select "Properties". Select the "Build" tab and change the "Configuration" drop down to "All Configurations". Set the "Output path" to bin\
5 Add Proxy References and End Points To Your Website
Add a reference to each proxy project to your website by right clicking "References > Add reference" and then going to the "Projects" Tab.
Now open up your web.config file and add the bindings, use your previous web.config as a guide.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="fooServiceEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="8192" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
<!-- Insert other binding as required -->
</basicHttpBinding>
</bindings>
<client>
<!-- Test Server Endpoints - Used for day-to-day development -->
<endpoint address="http:[Path to TEST Server service]"
binding="basicHttpBinding" bindingConfiguration="fooServiceEndpoint"
contract="FooService.Proxy.IFooService" name="fooServiceEndpoint" />
<!-- Add Other endpoints as required -->
<!-- Staging Server End Points - Used Occasionaly
<endpoint address="http:[Path to STAGING Server service]"
binding="basicHttpBinding" bindingConfiguration="fooServiceEndpoint"
contract="FooService.Proxy.IFooService" name="fooServiceEndpoint" />
<other end points here too />
-->
<!-- LIVEServer End Points - Used Rarely and with CAUTION
<endpoint address="http:[Path to LIVE Server service]"
binding="basicHttpBinding" bindingConfiguration="fooServiceEndpoint"
contract="FooService.Proxy.IFooService" name="fooServiceEndpoint" />
<other end points here too />
-->
</client>
</system.serviceModel>
Now you can simply modify the web config with comments depending on which server you want to be debugging on.
6 Set up web.config transformation for deployment
Expand the web.config node in the solution explorer.
Open the web.staging.config file and add the following:
<system.serviceModel>
<client>
<endpoint address="http:[Path to STAGING server Service]"
binding="basicHttpBinding" bindingConfiguration="fooServiceEndpoint"
contract="FooService.Proxy.IFooService" name="fooServiceEndpoint" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</client>
<!-- Repeat for additional end points -->
</system.serviceModel>
Now add the same to Web.Release.Config changing the paths to tho the LIVE server paths. This will now use the appropriate endpoints when published using the VisualStudio publish command.
E.g. If deploying a STAGING version of the web site, select "Staging" from the Build Configuration drop down. Right click on the WebSite project in the solution explorer and select "Publish". Choose how you wish to publish and click the "Publish" button. The whole solution will then rebuild, proxies will be generated form the Staging server and the web.config file will be published with the Staging setting.
That's it, you're done
You now have proxies that will generate based on your build configuration, one location to change paths via commenting for debugging purposes, and automatic web.config updating on publishing.
Update
Gaui, the OP, has created a small exe that simplifies this somewhat. It is available on GitHub.

I've had a lot of problems with this, too. But I ended up in finding a nice and easy way. My example with a fictious service address:
Create a command line EXE
Add service reference with address https://service.somePortal.com/FooConnector.svc and namespace "MyServiceReference"
Let's say the service is offering an Interface "IFooConnector". Choose OK to generate (a lot of) code to consume the service.
After that, in your App.config file you will see a new serviceModel section:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="NetHttpsBinding_IFooConnector">
<binaryMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://service.somePortal.com/FooConnector.svc"
binding="customBinding" bindingConfiguration="NetHttpsBinding_IFooConnector"
contract="MyServiceReference.IFooConnector" name="NetHttpsBinding_IFooConnector" />
</client>
</system.serviceModel>
You can now use a service method like this:
using TestClient.MyServiceReference;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
using (var client = new FooConnector())
{
client.DoSomething();
}
}
}
}
Now the important part:
To use three inkarnations of the same service, like DEV (Development), TEST (Testing) and PROD (Production) at different addresses, but having the same interface, you only have to manually edit your App.config and use a different constructor to instantiate the client!
Here's the new App.config with the changed serviceModel section:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="NetHttpsBinding_IFooConnector">
<binaryMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://dev-service.somePortal.com/FooConnector.svc"
binding="customBinding" bindingConfiguration="NetHttpsBinding_IFooConnector"
contract="MyServiceReference.IFooConnector" name="DEV" />
<endpoint address="https://test-service.somePortal.com/FooConnector.svc"
binding="customBinding" bindingConfiguration="NetHttpsBinding_IFooConnector"
contract="MyServiceReference.IFooConnector" name="TEST" />
<endpoint address="https://service.somePortal.com/FooConnector.svc"
binding="customBinding" bindingConfiguration="NetHttpsBinding_IFooConnector"
contract="MyServiceReference.IFooConnector" name="PROD" />
</client>
</system.serviceModel>
As you see, we're now having three endpoint sections with different service addresses. I've also changed the endpoints name properties to match my desired DEV, TEST and PROD naming.
To call the required service you can now use a different constructor of the client, having one parameter: string endpointConfigurationName.
So you can now use the same service method in its three inkarnations like this:
using TestClient.MyServiceReference;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
using (var client = new FooConnector("DEV"))
{
//Call method in DEV
client.DoSomething();
}
using (var client = new FooConnector("TEST"))
{
//Call method in TEST
client.DoSomething();
}
using (var client = new FooConnector("PROD"))
{
//Call method in PROD
client.DoSomething();
}
}
}
}
That's it! :-)
P.S.: In my real project, I have an enum user setting to choose DEV, TEST, PROD to change the used service by configuration.

One technique is to get the endpoint and replace the URL in code (e.g., you can do it from a database), with something like this:
endpoint.Endpoint.Address = new System.ServiceModel.EndpointAddress(remoteUrl);

Related

Please indicate the preferred endpoint configuration section by name

Before some one commenting that it is a duplicate, please note that i have gone through the suggestions given in internet.
Scenario:
I am having a web api call and have only one end point in the webconfig`
<client>
<endpoint address="http://localhost/RegistrationService/RegistrationService.svc"
binding="basicHttpBinding" bindingConfiguration="RegistrationService"
contract="RegistrationService.IRegistrationService" name="RegistrationService" />
<endpoint address="http://localhost/ElectronicCustomerFileService/ElectronicCustomerFileService.svc"
binding="basicHttpBinding" bindingConfiguration="ElectronicCustomerFileService"
contract="ElectronicCustomerFileService.IElectronicCustomerFileService"
name="ElectronicCustomerFileService" />
</client>
`
following is the binding equivalent
`
<bindings>
<basicHttpBinding>
<binding name="RegistrationService" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" />
</binding>
<binding name="ElectronicCustomerFileService" />
</basicHttpBinding>
</bindings>
`
While i run the application i am getting error
An endpoint configuration section for contract 'ElectronicCustomerFileService.IElectronicCustomerFileService' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.
Tools Used
I am using Visual studio 2017 . I had Visual Studio 2019 and uninstalled it thinking that the issue is due to visual studio version issue
Interesting Fact
If i remove the end point from the webconfig , and try connecting to the web api, it is working properly . I checked the folder to see if any other webconfig is there in root folder and cannot find it
From where this web config is getting called
I restarted IIS. Deleted temporary files in Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files. But not working
It seems like the default website directory was pointing to a different project location
Go to IIS manager
Select Default Web site
go to basic setting in right hand side
Check if the Physical path is pointing to a different location
If the path is not pointing to above, change the physical path to
%SystemDrive%\inetpub\wwwroot

Build transformations when publishing multiple-websites WebRole

I have added multiple sites inside a azure web role, like below:
<WebRole name="site1" vmsize="Small">
<Sites>
<Site name="site1" physicalDirectory="..\site1">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.site1.nl" />
</Bindings>
</Site>
<Site name="site2" physicalDirectory="..\site2">
<Bindings>
<Binding name="ndpoint1" endpointName="Endpoint1" hostHeader="www.site2.nl" />
</Bindings>
</Site>
</Sites>
......
I have added two configurations for each web application to make database connection string different -> Web.Dev.Config and Web.Staging.Config.
When i right click the Cloud Service projcet -> 'Publish', and choose the 'Build configuration' to 'Dev', these two web site were be published successful.
But in the site2, the connection string inside Web.config seems incorrect , the folder of site2 contains all configurations of web.config files like Web.Dev.config and Web.Staging.config, and all cs files still exists, it seems the site2 was not build correctly.
Is there anybody has experience about this?
I have the same issue, but I've found a few other articles that explain how to resolve this.
https://kellyhpdx.wordpress.com/2012/04/11/deploying-multiple-web-applications-to-a-single-azure-instance-and-applying-web-config-transforms-correctly/
Windows Azure with Multiple Sites in One Role not transforming 2nd web.debug.config to web.config

visual studio putting wrong path for virutalDirectory in applicationhost.config?

I recently moved my "My Documents" folder from the C: to the D: drive. This seems to have broken my ability to debug web app in Visual Studio. I'm assuming that visual studio creates entries like the following in applicationhost.config, and I am wondering where the first physicalPath for the root virtualDirectory comes from, as I am fairly certain that is the problem (I've pretty much confirmed that VS creates an entry like the following when a solution is opened):
<site name="My.Application-Site" id="2">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\Users\myname\Documents\My Web Sites\My.Application-Site" />
</application>
<application path="/My" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="D:\repos\MyCheckout\My\My.Application" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:49924:localhost" />
</bindings>
</site>
When I try to run the app in debugger, the browser pops up with an error, the relevant bits of which are below. Notice the path to web.config still uses C:, even though it seems to know the right place for tracelogfiles:
HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
Config Error Cannot read configuration file
Config File \\?\C:\Users\myname\Documents\My Web Sites\My.Application-Site(2)\web.config
Requested URL http://localhost:50616/My/
Request Tracing Directory D:\users\myname\My Documents\IISExpress\TraceLogFiles\
So the question is where in Visual Studio (or IIS) is the path for the web.config file determined, and how do I change it. And/or is there some other reason or insight anyone can provide as to why I am getting this 500.19 error?
Another recent change (other than moving My Documents) is I uninstalled a trial of VS Ultimate 2013 and installed VS Pro 2013 -- could that have somehow caused this? Both of changes have been made between the time I was last able to debug the app normally and getting this error.
For someone looking for an answer to "where in Visual Studio (or IIS) is the path for the web.config file determined, and how do I change it" or "I moved my application from its origin folder"
Right-click in Project Properties > Web Tab and Create Virtual Directory buttom.
It all happened when I was developing (and debuging, of course) my application on two different machines, with different paths (and Drives) to the source code managed by git.
Hope it helps

Adding custom section to web.config in ASP.NET 4

I've spent half of a day trying to understand why the following fails.
I can add section anywhere but never got it working like that ():
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<mysection />
<system.web>
<compilation debug="false" batch="false" targetFramework="4.0" />
</system.web>
<system.webServer>
<handlers>
</handlers>
</system.webServer>
</configuration>
I think the error related to .NET 4, because when you put section without pre-configuration in applicationHost.config it shows error with gray border saying that config is incorrect. That is what I expect. Then I add section definition and everything seems to work I can edit config from console - this means it is parsed correctly now.
But when I try to reach Application, it gives:
Parser Error Message: Unrecognized configuration section mysection
with a piece of config on yellow background.
Or do I need to write a module to consume that settings ? At the moment I do not have any, just a text in config.
following links will help you understand for this.
http://www.codeproject.com/Articles/32628/ASP-NET-Custom-Web-Configuration-Section
https://web.archive.org/web/20211020133931/https://www.4guysfromrolla.com/articles/032807-1.aspx
Regards,
Old topic but these links are very helpfull:
http://www.iis.net/learn/develop/extending-iis-configuration/configuration-extensibility
http://www.iis.net/learn/develop/extending-iis-configuration/extending-iis-schema-and-accessing-the-custom-sections-using-mwa
Edit (05/25/2016) :
The Details of how to store custom information in applicationHost.config file ... I hope this helps !
Note : These settings wont be visible on IIS Manager. There is a way to do that but thats beyond the scope of this response.
Requirement:
Need to extend the system.applicationHost/sites section of applicationHost.config file to allow a siteowner attribute at the site level. (IIS Does not allow us to do this by default). Nor can you manually edit the applicationHost.config file and add custom tags/attributes.
Steps:
Create a custom schema ( xml ) file under %windir%\system32\inetsrv\config\schema\ . File name: siteExtension_schema.xml
Include the custom elements that you want to eventually save in the applicationHost.config in that xml and save it with a appropriate name. The crucial thing to keep in mind is the sectionSchema tag.So when extending the schema of an existing section, simply create a element and set the name attribute to be the same as an existing section. In the schema file (see below), we have defined a with a name of "system.applicationHost/sites" - this is the same as the sectionSchema name in the default IIS_Schema.xml file in the Schema directory. So in essence you are instructing IIS to add these
<!-- Contents of %windir%\system32\inetsrv\config\schema\siteExtension_schema.xml -->
<configSchema>
<sectionSchema name="system.applicationHost/sites">
<collection addElement="site">
<attribute name="owner" type="string" />
<attribute name="ownerEmail" type="string" />
</collection>
</sectionSchema>
</configSchema>
Test the modifications by adding values for the "owner" and "ownerEmail" attributes that we included in step 2 above and then check the configuration file (applicationHost.config) to see the changes. Simply run the following command (must be elevated as Administrator) from the command line (uses appcmd ) to do so:
C:\> %windir%\system32\inetsrv\appcmd set site "Default Web Site" /owner:"John Contoso" /ownerEmail:"john#contoso.com"
To see if the configuration was applied, run the following command and check the output:
C:\> %windir%\system32\inetsrv\appcmd list site "Default Web Site" /config
<system.applicationHost>
<sites>
...
<site name="Default Web Site" id="1" siteOwner="John Contoso" siteOwnerEmail="john#contoso.com">
...
...
</site>
</sites>
</system.applicationHost>
To Read and Write your settings programmatically thru C# :
//this Will work with the ServerManager.OpenRemote("MyRemoteHostname") method also
using(var mgr = new ServerManager())
{
//Read
Console.WriteLine(mgr.Sites["Default Web Site"].Attributes["owner"].Value ); //Prints "John Contoso"
//Write
mgr.Sites["Default Web Site"].Attributes["owner"].Value = "New Owner";// Sets new value
mgr.CommitChanges(); // commits the changes to applicationHost.Config
}

using web.config variables within web.config

I would like to have a variable defined in my web.config that I can use in multiple places within my web.config file (and other config files). It's probably easier to explain by example ...
web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="AuthServiceEndPoint" value="any_old_name_i_like"/>
</appSettings>
<system.web>
...
<system.serviceModel>
<client>
<endpoint
address="net.tcp://localhost/AuthService"
binding="netTcpBinding"
contract="MyServices.Contracts.IAuthService"
name="#{AppSettings.AuthServiceEndPoint}"
bindingConfiguration="netTcpBindingConfig"
/>
</client>
</system.serviceModel>
</configuration>
windsor.config
<?xml version="1.0" encoding="utf-8" ?>
<castle>
<components>
...
<component
id="AuthProvider"
service="MyServices.Client.IAuthProvider, MyServices.Client"
type="MyServices.Client.AuthProvider, MyServices.Client"
lifestyle="transient">
<parameters>
<endpoint>#{AppSettings.AuthServiceEndPoint}</endpoint>
</parameters>
</component>
</components>
</castle>
Is this possible?
Edit (a bit more information)
I already have the ability to access the AppSettings from my windsor.config file (which is actually processed by castle windsor and a custom XmlInterpreter.
The real question is can I do this in my web.config?
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="AuthServiceEndPoint" value="any_old_name_i_like"/>
</appSettings>
<system.web>
...
<system.serviceModel>
<client>
<endpoint
address="net.tcp://localhost/AuthService"
binding="netTcpBinding"
contract="MyServices.Contracts.IAuthService"
name="#{AppSettings.AuthServiceEndPoint}"
bindingConfiguration="netTcpBindingConfig"
/>
</client>
</system.serviceModel>
</configuration>
ie - access variable in my <appSettings> from other parts of my web.config file.
Off the top of my head, I wonder if you might be able to do this with T4? I'm thinking that perhaps you could define a template which parses Web-Template.config and outputs Web.config? Of course, this only works for a single file.
You can use NAnt or MSBuild for this. You do need separate configuration files for both, but when you build your project they can automatically do transformations on your Web.config and other configuration files.
Not that I can think of. You could do your configuration in C# in global.asax.cs instead of the xml file.
Alternatively, have your web.config edited by your build process to replace all these values. FinalBuilder has a neato "Edit XML File" action that uses XPath quite well to do this, and FinalBuilder does have variables. Problem solved. This is how I do my builds at work.
Here I go answering my own question again :-S
I solved this by writing a NetTcpServiceLocator ...
public interface INetTcpServiceLocator
{
EndpointAddress GetAddress(Type serviceType);
}
... along with a custom config section handler which also implements the above interface and reads in the following config section ...
<services>
<service contract="My.Services.TestService.Contracts.ITestService" address="net.tcp://localhost/TestService" />
</services>
Then I created a proxy for each service ...
public class TestServiceProxy : ITestService
{
public SomeInformation GetSomeInformation(SomeParams #params)
{
using (var factory = new NetTcpServiceFactory<ITestService>())
{
var service = factory.Service;
return service.GetSomeInformation(#params);
}
}
}
My Controller has a dependency on a Service, which has a dependancy on ITestService. All this is glued together with Castle Windsor and by using property dependency injection.
So, my controller calls it's Service, which in turn calls the ITestService (in this case a proxy, which gets it's endpoint from the custom section handler).
The custom section handler (which is also the INetTcpServiceLocator) has a windsor lifestyle of "perWebRequest", so it gets called by the framework and web.config is read into an array in memory. When the service proxy is called, it then just pulls the relevant endpoint based on the contract type.
It's all driven by the type of the contract, so there is no need to have any variables in web.config anymore.
I've gone for a code based solution, as I don't use a build process locally, only when I submit my code to subversion does the build process kick in on our build server.

Resources