Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic endpoints in ServiceReferences.ClientConfig

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.

like image 803
randoms Avatar asked Sep 09 '11 10:09

randoms


2 Answers

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 :)

like image 93
randoms Avatar answered Oct 13 '22 00:10

randoms


Great solution to the problem
I could not get the <ItemGroup></ItemGroup> section to work effectively in my solution.
I removed it and added the following script to my Prebuild event in the project:

del $(ProjectDir)ServiceReferences.ClientConfig;
copy $(ProjectDir)ServiceReferences.$(ConfigurationName).ClientConfig $(ProjectDir)ServiceReferences.ClientConfig;
like image 21
Yossi Avatar answered Oct 12 '22 23:10

Yossi