我有一个带有15个WCF / ASMX服务引用的C#ASP.NET项目。每个服务都部署到三个不同的服务器; test
,staging
和live
。
通常我们需要将这些服务引用的URL更改为不同的服务器,以便能够使用正确的服务和正确的实现和数据进行调试。
管理这些服务引用时,我很难保持URL同步。创建服务引用FooService
时,它将URL存储在三个单独的文件中:
同时使用endpoint
中的网址创建Web.config
节点。
如果我在Web.config中更改端点URL并重建项目,它不会更新其他文件中的URL,因此它不同步。因此,当我右键单击FooService
并点击Update Service Reference
时,它不会使用Web.config
中存储的网址,而是使用其他文件中的网址。
因此,唯一的方法是右键点击FooService
并点击Configure Service Reference
并输入新网址。但这并不总是有效,因为有时它会在名为FooService1
的Web.config中创建一个新节点,因此在运行我的应用程序时会出现错误,说明有两个相同端点的实例。
因此,我经常需要浏览Web.config并删除端点的重复项,这非常令人沮丧。
在经常更改服务的URL时,管理多个WCF服务引用的最佳方法是什么?
答案 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\
等。我将看看我是否能找到更好的解决方案。
右键单击开始菜单中的Visual Studio,然后选择"以管理员身份运行"。我们需要这样做,因为VS将编写文件。
你不需要任何帮助。
现在执行此操作意味着您只需要为test | staging | live配置一次解决方案。
从文件菜单中选择"添加"然后"新项目"来自" Visual C#" tmplates select" Class Library"并将其命名为合理的。我将在此示例中使用FooService.proxy
。重命名类文件,我将在此示例中使用FooService_proxy.cs
。
将以下引用添加到项目中:
为每项服务添加一个项目。我们稍后会回来并更新这些项目。
我假设您在本地计算机上开发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。
通过单击解决方案资源管理器中的项目并选择"添加>,将批处理文件添加到每个代理项目新物品"。使用文本文件并将其命名为" 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\
通过右键单击&#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配置
展开解决方案资源管理器中的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)
我也遇到了很多问题。但我最终找到了一个简单易行的方法。我的例子有一个虚假的服务地址:
之后,在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来通过配置更改使用过的服务。