ServiceReferences.ClientConfig中的动态端点

时间:2011-09-09 10:50:03

标签: c# silverlight wcf-binding

构建应用程序时,它通常部署在不同的环境(test,dev,prod)中,因此端点地址正在发生变化。由于ServiceReferences.ClientConfig是作为Silverlight的.xap文件的一部分构建的,因此在构建解决方案后很难更改端点,这通常是通过web.config完成的。

我已经搜索了很多,但是我不知道这里的最佳做法是什么,所以我的问题是:

Silverlight中动态wcf端点地址配置的最佳做法是什么?

澄清一下,根据应用程序所在的服务器(test,dev,prod),端点会发生变化:

  <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"
             />

在某种程度上,我需要Silverlight客户端知道要使用哪一个,具体取决于它在哪个服务器上/哪个构建编译。

5 个答案:

答案 0 :(得分:26)

在阅读了sLedgem的帖子以及一些谷歌搜索之后,我找到了使ServiceReferences像web.config一样的完美解决方案。

首先: 手动创建不同的文件;

ServiceReferences.Debug.ClientConfig
ServiceReferences.Release.ClientConfig

如果在Visual Studio中有两个以上的默认配置,也可以添加自己的。

第二: 在Project.csproj文件中添加文件依赖项(在文本编辑器中打开项目文件):

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

现在,当您重新加载项目时,您将看到ServiceReferences.Release.ClientConfig可以在解决方案资源管理器中展开,当您展开它时,您将看到Release和Debug文件。

第三步:在结束</Project>

之前将转换规则添加到项目文件中

(再次,在文本编辑器中打开)

<!-- 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>

它的作用是查看相应的servicereferences文件,具体取决于您的配置,并使用web.config使用的相同TransformXML库复制/替换代码。

示例:

在我的ServiceReferences.ClientConfig中,我有以下代码:

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

如您所见,将替换端点,并在name属性上完成匹配。

如果您有任何疑问,请告诉我们:)

答案 1 :(得分:6)

解决问题的很好方法
我无法让<ItemGroup></ItemGroup>部分在我的解决方案中有效运作。
我将其删除并将以下脚本添加到项目中的Prebuild事件中:

del $(ProjectDir)ServiceReferences.ClientConfig;
copy $(ProjectDir)ServiceReferences.$(ConfigurationName).ClientConfig $(ProjectDir)ServiceReferences.ClientConfig;

答案 2 :(得分:3)

您可以在运行时通过使用SL中的WCF客户端的构造函数来执行此操作,该构造函数采用端点配置名称和地址。端点配置名称在您的示例中只是“MyService”。您提供的地址参数将覆盖ClientConfig中包含的参数。

在运行期间从SL计算服务地址的方法之一是(我不保证它可以在每个环境配置中使用):

  1. 计算您网站的根目录,例如通过找到共同的部分 Application.Current.Host.Source.AbsoluteUri和 HtmlPage.Document.DocumentUri.AbsoluteUri。基本上,你采取 字符从较短路径的开头只要它们 在另一条路径中匹配不区分大小写的字符。
  2. 附加服务的相对路径(如果有的话)(这里似乎不是这种情况)。
  3. 附加MyService.svc
  4. 额外信息:

    当你有很多服务时,这可能看起来很复杂,但它可以很好地重构,并且在Unity的帮助下很容易用于任何服务。例如,我使用一个辅助函数来注册一个服务客户端,它的调用如下所示:ServicesHelper.RegisterService&lt; MyServiceContractClient,IMyServiceContract&gt;(“MyService”);当我需要创建服务客户端的实例时,我只需使用Unity解析MyServiceContractClient类型,它使用注入构造函数来创建已正确配置的新服务实例。它还可以处理HTTPS情况。如果您需要有关此类信息的更多信息,请与我们联系。

答案 3 :(得分:1)

看看这里:

http://weblogs.asp.net/srkirkland/archive/2009/10/13/common-web-config-transformations-with-visual-studio-2010.aspx

然后在这里

http://www.funkymule.com/post/2010/03/08/XML-Transform-on-Silverlight-ClientConfig-Files.aspx

它使用了web.config转换背后的相同原理(即,web.config根据您正在编译的配置(即发布,调试)而更改,以便在编译时根据您的心血来潮改变serviceref.config有魅力的作品

答案 4 :(得分:1)

除了一件小事之外,randoms的反应很明显。不要将.Debug.ClientConfig和.Release.ClientConfig标记为“内容”。将它们标记为“无”。这样你的.Debug.ClientConfig和.Release.ClientConfig就不会被放入.xap文件中。这是我的Silverilght项目文件中的内容(并且效果很好):

<Content Include="ServiceReferences.ClientConfig">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="ServiceReferences.DEV.ClientConfig">
  <DependentUpon>ServiceReferences.ClientConfig</DependentUpon>
</None>
<None Include="ServiceReferences.TEST.ClientConfig">
  <DependentUpon>ServiceReferences.ClientConfig</DependentUpon>
</None>
<None Include="ServiceReferences.PROD.ClientConfig">
  <DependentUpon>ServiceReferences.ClientConfig</DependentUpon>
</None>