Trabajando con Ajax y las Microsoft Ajax Library (ScriptManager, UpdatePanel etc…) e IFrames: Como resolver el error “Access Denied”.

No es extraño, encontrarse con escenarios de integración de aplicaciones (hablamos de aplicaciones Web) donde tenemos que integrar nuestras apps con aplicaciones de terceros.

Una solución muy extendida, es hacerlo con la ayuda de IFrames, donde en el cargamos nuestra aplicación en un sitio de terceros, de manera que la aplicación de terceros (donde integramos la nuestra) está en un servidor y nuestra aplicación esta en otro servidor.

Si nuestra aplicación, está trabajando con Ajax (y con ScriptManager, UpdatePanel etc…), seguramente cuando la ejecutemos en Internet Explorer (solo lo he probado con IE7 aunque tengo sospechas de que ocurrirá también con IE6) vamos a recibir un error cuya descripción es “Access Denied”.

¿Qué es el ScriptManager?

El ScriptManager, es un control de servidor que nos proporciona el Framework que nos va a gestionar  la descarga de los archivos necesarios de JavaScript  para poder trabajar con Ajax de forma sencilla.

Además, el ScriptManager, también inicializa valores del JavaScript etc… Así que tendremos que estar pendientes del uso que estamos haciendo de este para poder replicar su comportamiento.

¿Qué produce el error?

El error, lo produce la función getLocation del archivo MicrosoftAjax.js. El archivo MicrosoftAjax.js es uno de los que nos descarga el ScriptManager.

La función getLocation determina las coordenadas relativas de un pixel de un elemento del DOM respecto a la esquina superior izquierda del navegador. Como los distintos navegadores, esto lo calculan de distinta forma, esta función hace distinción del browser (algunos tienen en cuenta el scroll otros no etc…) que está ejecutando la página (he aquí la razón por la que únicamente falla en Internet Explorer) así que nos encontramos con que la parte de código que calcula las coordenadas para Internet Explorer, no lo hace demasiado bien.

¿Cómo solucionar el error?

Pues bien, dado que tenemos localizada la razón por la que se produce el error, la solución es sencilla, tenemos hacer un wrapper del código que produce el susodicho error.

El wrapper, lo podemos realizar de varias formas aunque todas vienen a ser lo mismo así que vamos a buscar el siguiente código:

switch(Sys.Browser.agent)
{
case Sys.Browser.InternetExplorer:
...
break;

y vamos a sustituir el código del case por el siguiente:

Sys.UI.DomElement.getLocation = function(element) {
if (element.self || element.nodeType === 9) return new Sys.UI.Point(0,0);
var clientRect = element.getBoundingClientRect();
if (!clientRect)
{
return new Sys.UI.Point(0,0);
}
var ownerDocument = element.document.documentElement;
var offsetX = clientRect.left - 2 + ownerDocument.scrollLeft,
offsetY = clientRect.top - 2 + ownerDocument.scrollTop;
try
{
var f = element.ownerDocument.parentWindow.frameElement || null;
if (f)
{
var offset = 2 - (f.frameBorder || 1) * 2;
offsetX += offset;
offsetY += offset;
}
}
catch(ex)
{
}
return new Sys.UI.Point(offsetX, offsetY);
}

Fácil verdad, pues eso es todo, este código no levanta el error al calcular las coordenadas de un elemento y funciona de maravilla.

Ahora bien, donde tenemos que colocar este código, según he leído por ahí basta con incluirlo en las páginas (o master page) dentro del tag script de la siguiente manera:

<script language=”JavaScript” type=”text/JavaScript”>
Sys.UI.DomElement.getLocation = function(element) {
if (element.self || element.nodeType === 9) return new Sys.UI.Point(0,0);
var clientRect = element.getBoundingClientRect();
if (!clientRect)
{
return new Sys.UI.Point(0,0);
}
var ownerDocument = element.document.documentElement;
var offsetX = clientRect.left - 2 + ownerDocument.scrollLeft,
offsetY = clientRect.top - 2 + ownerDocument.scrollTop;
try
{
var f = element.ownerDocument.parentWindow.frameElement || null;
if (f)
{
var offset = 2 - (f.frameBorder || 1) * 2;
offsetX += offset;
offsetY += offset;
}
}
catch(ex) {
}
return new Sys.UI.Point(offsetX, offsetY);
}
</script>

Este código aunque no lo he probado, creo que funcionara y aunque es simple (y generalmente las soluciones más simples son las mejores) no me parece lo más elegante, hay otra solución que me gusta algo más que lo que viene a decir, es que descarguemos las Microsoft Ajax Library y modifiquemos este código en el archivo MicrosoftAjax.js (o en el MicrosoftAjax.debug.js que es mucho más sencillo de usar ya que el contenido es el mismo pero nos viene identado) y lo incluyamos en la página como ScriptReference por medio del ScriptManager de la siguiente manera:

<asp:ScriptManager ID="ScriptManager" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/ScriptManager/MicrosoftAjax.js"
</Scripts>
</asp:ScriptManager>

Esta solución aunque me gusta más porque así tenemos el código modificado en un único sitio y nos va a ser más simple mantenerlo tampoco me termina de convencer porque lo que va a ocurrir es:

  1. El ScriptManager gestiona la descarga de los archivos JavaScript necesarios para trabajar con Ajax (entre los cuales se incluye el MicrosoftAjax.js).
  2. Una vez descargados los archivos JavaScript que lo sustituyen en cliente procede a la descarga de los archivos JavaScript vinculados por medio de ScriptReference. Como hemos podemos ver, por medio del ScriptReference le estamos indicando que use el archivo donde hemos modificado el código que producía el error, por lo tanto lo sobrescribirá y funcionara ok.

Esto la mayor parte de los casos por no decir el 100% de los casos va a funcionar bien, es decir primero descarga los archivos JavaScript que sustituyen en la parte cliente al ScriptManager y luego descarga los ScriptReferences (esto se puede comprobar de forma muy sencilla con el herramienta de monitorización que incluye firebug), pero ya sabéis mis druguitos que todo puede ocurrir así que ¿Qué pasaría si se descargan antes los ScriptReferences que los archivos que renderiza el ScriptManager? pues que otra vez se volvería a producir el error.

Así pues, para alejar la duda de nuestras cabezas, vamos a modificar el archivo MicrosoftAjax.js (o MicrosoftAjax.debuj.js) y vamos a eliminar el ScriptManager de nuestra página. Esto ya vimos anteriormente como hacerlo y no es muy complejo y por el contrario nos vamos a asegurar:

  • El error nunca se va a replicar.
  • Vamos a tener el código modificado en un solo sitio (es decir va a ser mucho más mantenible porque en caso de tener que modificarlo vas a hacerlo en un único sitio).
  • Y todo lo que aporta el eliminar el ScriptManager (el servidor no tiene que preprocesar nada, estos archivos JavaScript se van a cachear etc..).

Post relacionados.

Descargas – Downloads

No olvideis montar WebSites distintos para poder probar esto, si no de nada sirve.

Mientras he escrito este post, he escuchado el Outside de David Bowie, así que os dejo con él.

Un pensamiento en “Trabajando con Ajax y las Microsoft Ajax Library (ScriptManager, UpdatePanel etc…) e IFrames: Como resolver el error “Access Denied”.

  1. Como eliminar el ScriptManager de nuestra página y que el desarrollo Ajax siga funcionando igual. « a deshoras

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s