When building an app, it is often deployed in different environments (test, dev, prod), and therefore the endpoint addresses are changing. As the ServiceReferences.ClientConfig is built as a part of Silverlight's .xap file, its hard to change the endpoints after building the solution, as often is done with web.config.
I've searched quite a bit for it, but I cant figure out what is best practice here, so my question is:
What is best practice when it comes to dynamic wcf endpoint address configuration in silverlight?
To clarify, depending on which server the app is on (test,dev, prod) the endpoints change:
<endpoint
name="MyService"
address="http://testserv/MyService.svc"
binding="basicHttpBinding"
bindingConfiguration="MybasicHttpBinding"
contract="MyApp.MyService"
/>
<endpoint
name="MyService"
address="http://prodserv/MyService.svc"
binding="basicHttpBinding"
bindingConfiguration="MybasicHttpBinding"
contract="MyApp.MyService"
/>
In some way, i need the silverlight client to know which one to use, depending on which server its on / which build is compiled.
After reading sLedgem's post, and some googling, I found the perfect solution to make ServiceReferences act like web.config.
First off: Create the different files manually;
ServiceReferences.Debug.ClientConfig
ServiceReferences.Release.ClientConfig
You can add your own as well if you have more than the two default configurations in Visual Studio.
Second: Add the file dependency in the Project.csproj file (Open the project file in a text editor):
<ItemGroup>
<None Include="Properties\AppManifest.xml" />
<Content Include="ServiceReferences.ClientConfig">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="ServiceReferences.Debug.ClientConfig">
<DependentUpon>ServiceReferences.ClientConfig</DependentUpon>
</Content >
<Content Include="ServiceReferences.Release.ClientConfig">
<DependentUpon>ServiceReferences.ClientConfig</DependentUpon>
</Content >
</ItemGroup>
Now, when you reload the project, you will see that ServiceReferences.Release.ClientConfig is expandable in the Solution Explorer, and when you expand it, you will see the Release and Debug file.
Third: Add the Transformation rules to the Project file just before the closing </Project>
(again, open it in a text editor)
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. -->
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="exists('ServiceReferences.$(Configuration).ClientConfig')">
<!-- Generate transformed ServiceReferences config in the intermediate directory -->
<TransformXml Source="ServiceReferences.ClientConfig" Destination="$(IntermediateOutputPath)$(TargetFileName).ClientConfig" Transform="ServiceReferences.$(Configuration).ClientConfig" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<ServiceReferencesConfigWithTargetPath Remove="ServiceReferences.ClientConfig" />
<ServiceReferencesConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).ClientConfig">
<TargetPath>$(TargetFileName).ClientConfig</TargetPath>
</ServiceReferencesConfigWithTargetPath>
</ItemGroup>
</Target>
What it does is to look in the corresponding servicereferences file, depending on your configuration, and copy / replace code using the same TransformXML library that web.config uses.
Example:
in my ServiceReferences.ClientConfig i have the following code:
<endpoint name="ICatalogueService"
address="address"
binding="basicHttpBinding"
bindingConfiguration="My_basicHttpBinding"
contract="Services.ServiceInterfaces.ICatalogueService"/>
ServiceReferences.Release.ClientConfig:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.serviceModel>
<client>
<endpoint
name="ICatalogueService"
address="http://server/Services/CatalogueService.svc"
binding="basicHttpBinding"
bindingConfiguration="My_basicHttpBinding"
contract="Services.ServiceInterfaces.ICatalogueService"
xdt:Transform="Replace" xdt:Locator="Match(name)" />
</client>
<extensions />
</system.serviceModel>
</configuration>
As you can see, the endpoint will be replaced, and the match is done on the name attribute.
If you have any questions, let me know :)