c# - Puntos finales dinámicos en ServiceReferences.ClientConfig
silverlight wcf-binding (5)
Al crear una aplicación, a menudo se implementa en diferentes entornos (test, dev, prod) y, por lo tanto, las direcciones de los puntos finales están cambiando. Como el ServiceReferences.ClientConfig se construye como parte del archivo .xap de Silverlight, es difícil cambiar los puntos finales después de compilar la solución, como suele ocurrir con web.config.
Lo he buscado bastante, pero no puedo averiguar qué es la mejor práctica aquí, así que mi pregunta es:
¿Cuál es la mejor práctica cuando se trata de la configuración dinámica de direcciones de punto final de wcf en Silverlight?
Para aclarar, según el servidor en el que se encuentre la aplicación (test, dev, prod), los puntos finales cambian:
<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"
/>
De alguna manera, necesito que el cliente de Silverlight sepa cuál usar, según el servidor en el que está compilada la compilación.
Después de leer la publicación de sLedgem y algunas búsquedas en Google, encontré la solución perfecta para hacer que las referencias de servicio actúen como web.config.
En primer lugar: crea los diferentes archivos manualmente;
ServiceReferences.Debug.ClientConfig
ServiceReferences.Release.ClientConfig
También puede agregar el suyo propio si tiene más de las dos configuraciones predeterminadas en Visual Studio.
Segundo: Agregue la dependencia de archivo en el archivo Project.csproj (Abra el archivo de proyecto en un editor de texto):
<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>
Ahora, cuando vuelva a cargar el proyecto, verá que ServiceReferences.Release.ClientConfig es expandible en el Explorador de soluciones, y cuando lo expanda, verá el archivo de versión y depuración.
Tercero: agregue las reglas de transformación al archivo de proyecto justo antes del cierre </Project>
(de nuevo, ábrelo en un editor de texto)
<!-- 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>
Lo que hace es buscar en el archivo de referencias de servicio correspondiente, dependiendo de su configuración, y copiar / reemplazar el código usando la misma biblioteca TransformXML que utiliza web.config.
Ejemplo:
en mi ServiceReferences.ClientConfig tengo el siguiente código:
<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>
Como puede ver, el punto final será reemplazado, y la coincidencia se realiza en el atributo de nombre.
Si tiene alguna pregunta, hágamelo saber :)
Echa un vistazo aquí:
entonces aqui
http://www.funkymule.com/post/2010/03/08/XML-Transform-on-Silverlight-ClientConfig-Files.aspx
Utiliza el mismo principio detrás de las transformaciones web.config (es decir, web.config se cambia según la configuración que esté compilando (es decir, release, debug) para que el serviceref.config se modifique de acuerdo con su capricho en el momento de compilación. encanto
Gran solución al problema.
No pude conseguir que la <ItemGroup></ItemGroup>
en mi solución.
Lo quité y agregué la siguiente secuencia de comandos a mi evento Prebuild en el proyecto:
del $(ProjectDir)ServiceReferences.ClientConfig;
copy $(ProjectDir)ServiceReferences.$(ConfigurationName).ClientConfig $(ProjectDir)ServiceReferences.ClientConfig;
La respuesta de los randoms es acertada a excepción de UNA pequeña cosa. No marque .Debug.ClientConfig y .Release.ClientConfig como "Contenido". Marque como "Ninguno". De esa manera, su .Debug.ClientConfig y .Release.ClientConfig no se colocan en su archivo .xap. Aquí está lo que está en mi archivo de proyecto Silverilght (y funciona muy bien):
<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>
Puede hacerlo durante el tiempo de ejecución utilizando el constructor del cliente WCF en SL que toma el nombre de la configuración del punto final y la dirección. El nombre de la configuración del punto final es simplemente "MyService" en su ejemplo. El argumento de dirección que proporcione anulará el que se incluye en ClientConfig.
Una de las formas de calcular la dirección de su servicio durante el tiempo de ejecución desde SL es (no garantizo que funcionará en todas las configuraciones de entorno):
- Calcule la raíz de su sitio, por ejemplo, encontrando la parte común de Application.Current.Host.Source.AbsoluteUri y HtmlPage.Document.DocumentUri.AbsoluteUri. Básicamente, toma caracteres desde el principio de la ruta más corta siempre que coincidan con los caracteres que no distinguen mayúsculas y minúsculas en la otra ruta.
- Agregue la ruta relativa a los servicios si los hay (no parece ser el caso aquí).
- Añadir MyService.svc
Información extra:
Esto puede parecer complicado cuando tiene muchos servicios, pero todo puede ser bien refaccionado y con la ayuda de Unity es bastante fácil de usar para cualquier servicio. Por ejemplo, uso una función auxiliar que registra un cliente de servicio y su llamada se ve así: ServicesHelper.RegisterService <MyServiceContractClient, IMyServiceContract> ("MyService"); Cuando necesito crear una instancia del cliente de servicio, solo resuelvo el tipo MyServiceContractClient con Unity, que usa un constructor de inyección para crear una nueva instancia de mi servicio ya configurado correctamente. También puede manejar la situación HTTPS. Déjame saber si necesitas más información sobre algo de eso.