在.NET中管理多个服务引用的最佳方法

时间:2014-04-27 23:48:00

标签: asp.net .net wcf visual-studio-2012 service-reference

我有一个带有15个WCF / ASMX服务引用的C#ASP.NET项目。每个服务都部署到三个不同的服务器; teststaginglive

通常我们需要将这些服务引用的URL更改为不同的服务器,以便能够使用正确的服务和正确的实现和数据进行调试。

管理这些服务引用时,我很难保持URL同步。创建服务引用FooService时,它将URL存储在三个单独的文件中:

  • FooService.disco
  • configuration.svcinfo
  • Reference.svcmap

同时使用endpoint中的网址创建Web.config节点。

如果我在Web.config中更改端点URL并重建项目,它不会更新其他文件中的URL,因此它不同步。因此,当我右键单击FooService并点击Update Service Reference时,它不会使用Web.config中存储的网址,而是使用其他文件中的网址。

因此,唯一的方法是右键点击FooService并点击Configure Service Reference并输入新网址。但这并不总是有效,因为有时它会在名为FooService1的Web.config中创建一个新节点,因此在运行我的应用程序时会出现错误,说明有两个相同端点的实例。

因此,我经常需要浏览Web.config并删除端点的重复项,这非常令人沮丧。

在经常更改服务的URL时,管理多个WCF服务引用的最佳方法是什么?

3 个答案:

答案 0 :(得分:6)

首先概述

我处理它的方法是不通过Visual Studio添加服务引用。我所拥有的是每个服务在解决方案中拥有它自己的代理项目,使用简单的一行批处理文件创建代理。然后将这些中的每一个都包含在网站中作为"香草"参考。终结点在Web配置中以maunally配置。我有三个部署选项:Debug(本地),Staging和Release。在web.config级别,不同的地址由web.config transformations处理。配置代理项目文件,以便根据解决方案配置使用正确的端点地址。但是,重要的是要注意web.config转换仅适用于发布解决方案。

在VS2010之前,我有3个变种的web.config文件会覆盖活动的web.config;但是以这种方式覆盖web.config总是觉得"冒险"对我来说。在这种情况下,我认为使用转换进行发布仍然有效,但在实际的web.config文件中有一些连接块,当您想要调试登台或开发服务器时,可以对这些连接进行注释。

我只有2个服务,所以我的设置非常简单,15个设置会涉及相当多的工作,但从长远来看它会为你节省头痛。

实施

首先备份所有内容!!

还可以随时使用现有web.config的副本来帮助稍后配置端点。

另请注意,如果您的解决方案位于名称中包含空格的路径中,批处理文件将无法正常工作,例如:默认位置VS放置其'项目。我的所有项目都采用以下结构C:\Source\vs2008\C:\Source\vs2010\等。我将看看我是否能找到更好的解决方案。

0以管理员身份运行VisualStudio

右键单击开始菜单中的Visual Studio,然后选择"以管理员身份运行"。我们需要这样做,因为VS将编写文件。

1删除Exising服务引用

你不需要任何帮助。

2添加代理项目

现在执行此操作意味着您只需要为test | staging | live配置一次解决方案。

从文件菜单中选择"添加"然后"新项目"来自" Visual C#" tmplates select" Class Library"并将其命名为合理的。我将在此示例中使用FooService.proxy。重命名类文件,我将在此示例中使用FooService_proxy.cs

将以下引用添加到项目中:

  • System.Runtime.Serialization
  • System.ServiceModel

为每项服务添加一个项目。我们稍后会回来并更新这些项目。

3配置解决方案以处理test | staging | live

我假设您在本地计算机上开发asp.net网站时使用test

打开"配置管理器"在Build Configuration下拉菜单中选择它。

在" Active Solution Configuration"下拉菜单选择"新"

对于姓名我建议"分期"并检查"创建新的项目混淆"复选框。

在Solution Explorer中,右键单击Web.Config并选择" Add config transforms"。这将为staging web.config转换添加一个新文件。单击展开箭头,您将看到三个子文件:Web.Debug.Config,Web.Release.Config,Web.Staging Config。

4设置代理

通过单击解决方案资源管理器中的项目并选择"添加>,将批处理文件添加到每个代理项目新物品"。使用文本文件并将其命名为" CreateProxy.bat。

将以下内容插入新文件并保存:

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

现在右键单击代理项目,然后单击"卸载项目",在提示时保存。这将使我们能够进入并修改项目文件。右键单击现在为灰色的代理项目名称,然后选择"编辑"。

仅为结束</project>标记添加以下内容。请注意,您可能需要更改 路径SDKPath取决于您svcutil的位置。另外,请确保将FooService_proxy.cs命名为代理文件。

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

保存更改,然后右键单击灰色的项目名称,然后选择&#34;重新加载项目&#34;。

右键单击项目并选择构建,确保现在已填充代理文件。

设置每个代理项目,使其始终只构建其代理项目。 \bin目录,例如 bin\debug等。右键单击代理项目,然后选择&#34;属性&#34;。选择&#34; Build&#34;选项卡并更改&#34;配置&#34;下拉到&#34;所有配置&#34;。设置&#34;输出路径&#34;到bin\

5将代理参考和结束点添加到您的网站

通过右键单击&#34;参考&gt;为每个代理项目添加对您的webstie的引用。添加参考&#34;然后去&#34; Projects&#34;标签

现在打开你的web.config文件并添加绑定,使用你以前的web.config作为指南。

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

现在,您只需根据您想要在哪个服务器上进行评论来修改带有注释的Web配置

6为部署设置web.config转换

展开解决方案资源管理器中的web.config节点。

打开web.staging.config文件并添加以下内容:

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

现在将相同内容添加到Web.Release.Config,将路径更改为LIVE服务器路径。现在,使用VisualStudio发布命令发布时,将使用相应的端点。

E.g。如果部署STAGING版本的网站,请选择&#34; Staging&#34;从Build Configuraion下拉。右键单击解决方案expolorer中的WebSite项目,然后选择&#34; Publish&#34;。选择您希望发布的内容,然后点击&#34;发布&#34;按钮。然后整个解决方案将重建,代理将从Staging服务器生成,web.config文件将与Staging设置一起发布。

多数民众赞成,你已经完成了

您现在拥有将根据您的构建配置生成的代理,一个通过注释进行调试以更改路径的位置,以及在publising上自动更新web.config。

更新

高能,OP,已经创建了一个小的exe,简化了这一点。它可在GitHub

上获得

答案 1 :(得分:1)

一种技术是获取端点并在代码中替换URL(例如,您可以从数据库中执行此操作),具体如下:

endpoint.Endpoint.Address = new System.ServiceModel.EndpointAddress(remoteUrl);

答案 2 :(得分:1)

我也遇到了很多问题。但我最终找到了一个简单易行的方法。我的例子有一个虚假的服务地址:

  • 创建命令行EXE
  • 添加地址为http://xarray.pydata.org/en/stable/且命名空间为“MyServiceReference”
  • 的服务引用
  • 假设该服务提供了一个接口“IFooConnector”。选择“确定”以生成(大量)代码以使用该服务。

之后,在App.config文件中,您将看到一个新的 serviceModel 部分:

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

您现在可以使用这样的服务方法:

using TestClient.MyServiceReference;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new FooConnector())
            {
                client.DoSomething();
            }
        }
    }
}

现在重要的部分:

要在不同地址使用相同服务的三个版本,如DEV(开发),TEST(测试)和PROD(生产),但具有相同的界面,您只需手动编辑App.config并使用不同的构造函数来实例化客户端!

以下是带有更改的 serviceModel 部分的新App.config:

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

如您所见,我们现在有三个具有不同服务地址的端点部分。我还更改了端点 name 属性,以匹配我想要的DEV,TEST和PROD命名。

要调用所需的服务,您现在可以使用客户端的不同构造函数,其中包含一个参数: string endpointConfigurationName 。 因此,您现在可以在其三种墨迹中使用相同的服务方法,如下所示:

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();
            }
        }
    }
}

就是这样! : - )

P.S。:在我的真实项目中,我有一个枚举用户设置,可以选择DEV,TEST,PROD来通过配置更改使用过的服务。