El día de ayer me dediqué a actualizar un componente de WCF que tenemos para un tutorial que estamos desarrollando de ASMX hacia REST.
Todo funcionó muy bien y terminé rapídisimo, en 20 minutos mi componente estaba portado y probado usando un GET y regresando un JSON con el resultado esperado.
El problema fué cuando hicimos el deployment.
Normalmente los servidores que ocupan servicios compartidos se encuentran aprovisionados con diferentes ServerBinding dentro de la metabase, no solamente un URI… múltiples y diferentes headers para permitir el hospedaje de diferentes sitios.
Lo que sucede al subir el servicio .svc al servidor empecé a tener problemas. Primero por que el hoster no estaba detectando el archivo .svc y eso se debia a que mi directorio no estaba configurado como .NET application.
Después de solucionar ese problema me llegó el esperado This collection already contains an address with scheme http. There can be at most one address per scheme in this collection. Este error nos indica que ya tenemos una dirección con esquema http (puede ser otro hoster que lo puso inicialmente o bien).
Encontré este post en la página de foros de Microsoft el cual dice:
You might be able to work around this with a custom ServiceHostFactory, whose CreateServiceHost method looks through the Uri[] that IIS passes it, and filters out the extras so that only one Uri (the host header appropriate to the WCF service) is used. A trivial subclass that just overrides this one method and filters the Uri[] parameter and then calls into the base class might be sufficient.
http://msdn2.microsoft.com/en-us/library/aa702697.aspx
Brian McNamara [MSFT]
Entonces me dí a la tarea de modificar mi servicio para permitir esta activación y filtrar los extras. Fué muy sencillo y a continuación les pongo los pasos:
1. Añades using System.ServiceModel.Activation; a la clase de tu servicio.
2. Agrega las siguientes clases para permitir una activación personalizada:
public class MyServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
// Specify the exact URL of your web service
Uri webServiceAddress = new Uri("http://intellekt.ws/translatr/translatr_r.svc");
MyServiceHost webServiceHost = new MyServiceHost(serviceType, webServiceAddress);
return webServiceHost;
}
}
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{ }
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
3. Modificamos el archivo .svc para permitir que la activación sea por mi clase de servicio personalizada utilizando el atributo Factory.
<%@ServiceHost Language=C# Debug="true" Service="translatr_r" Factory="MyServiceHostFactory" CodeBehind="~/App_Code/translatr_r.cs" %>
4. Finalmente tenemos que modificar la configuración del web.config que nos permita modificar el comportamiento del servicio para habilitar intercambio de metadatos para publicación.
<behavior name="MyServiceBehavior" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
5. Le añadimos la configuración del comportamiento al servicio y el endpoint del metadato:
<service name="MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
6. Como estamos utilizando REST, recuerda que el binding del servicio será webHttp para lo cual creamos un nuevo comportamiento específico para el endpoint. Esto te puede servir en caso de que quieras tener varios endpoints con diferentes comportamientos dentro de tu web.config…
<behavior name="WebHttpBehavior">
<!–<enableWebScript />–>
<webHttp />
</behavior>
7. Esto va en <services />.
<endpoint binding="webHttpBinding" contract="Itranslatr_r"
behaviorConfiguration="WebHttpBehavior" />
Listo. Con esto tenemos nuestro servicio REST funcionando adecuadamente en el servidor compartido. Es un poco latoso de depurar localmente así que lo que les recomiendo hagan todo este proceso ya cuando esten listos en el deployment.
Espero que les haya servido este sencillo tutorial y cualquier duda no olviden escribirme.
Cheers!
Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.