Error MaxReceivedMessageSizeExceeded en Silverlight al manipular tablas de una base de datos

Cuando desde Silverlight utilizamos un servicio Web para conectarnos a una base de datos y rellenar con una de sus tablas un control DataGrid -del modo explicado en este artículo-, puede darse el caso de que nos encontremos con el siguiente error.



El cual nos informa que se ha sobrepasado el tamaño máximo de mensaje soportado por el enlace de tipo BasicHttpBinding, que emplea el canal de comunicación abierto por el servicio Web.


Esta situación sucede cuando la tabla de la base de datos que vamos a utilizar tiene un tamaño considerable; por ejemplo, en el caso de Northwind, el error se producirá si usamos la tabla Orders, pero funcionará correctamente con Products ya que su tamaño es menor.


El mencionado tamaño máximo para el mensaje transmitido por el servicio Web, es un valor que puede ajustarse en el archivo de configuración ServiceReferences.ClientConfig, situado en el proyecto Silverlight de la solución, como vemos en la siguiente figura.



Dentro de dicho archivo de configuración, los atributos maxBufferSize y MaxReceivedMessageSize, pertenecientes al elemento binding, contienen los valores que determinan este tamaño del mensaje, que por defecto se encuentra establecido a 65536, como vemos en el siguiente bloque de código.


<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name=»BasicHttpBinding_IWSDatos»
maxBufferSize=»65536″
maxReceivedMessageSize=»65536″>

<security mode=»None» />
</binding>
</basicHttpBinding>
</bindings>
<!–…–>


Teóricamente, si aumentamos el valor de estos atributos solucionaríamos el problema, asignando, por ejemplo, el tamaño máximo correspondiente al tipo int.


<binding name=»BasicHttpBinding_IWSDatos»
maxBufferSize=»2147483647″
maxReceivedMessageSize=»2147483647″>

Sin embargo esta solución no funciona, ya que al ejecutar la aplicación, el entorno de ejecución hace caso omiso de estos valores de configuración, persistiendo el error.


El truco para corregir el problema radica en asignar estos valores dentro del code-behind de la página XAML de Silverlight, en el evento Loaded del UserControl, por ejemplo.


En concreto, las operaciones que necesitamos realizar consisten en instanciar un tipo BasicHttpBinding, al que asignaremos el tamaño antes mencionado en sus propiedades MaxReceivedMessageSize y MaxBufferSize. Este objeto representa el tipo de enlace utilizado por el servicio.


Por otro lado instanciaremos un tipo EndpointAddress, al que pasaremos en su constructor la dirección del servicio Web. Este objeto representa la dirección que la aplicación Silverlight usará para comunicarse con el servicio.


Finalmente crearemos la instancia del servicio Web, pasando como parámetros a su constructor los objetos que acabamos de crear. El resto de operaciones consisten en las ya conocidas llamadas al método asíncrono del servicio, que se encargará de devolver la tabla de la base de datos; y la creación del manipulador de evento que será llamado cuando finalice el anterior método asíncrono. Todo ello lo vemos en el siguiente bloque de código.


using System.ServiceModel;
//….
public partial class Page : UserControl
{
//….
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// crear un objeto del tipo de enlace que utilizará el servicio
BasicHttpBinding oBinding = new BasicHttpBinding();
oBinding.MaxReceivedMessageSize = 2147483647;
oBinding.MaxBufferSize = 2147483647;

// crear el objeto con la dirección que el cliente –aplicación Silverlight–
// usará para comunicar con el servicio
EndpointAddress oEndpoint = new EndpointAddress(new Uri(«http://localhost:54338/WSDatos.svc»));

// instanciar el servicio
RefWSDatos.WSDatosClient wsDatos = new SLErrorMessageSize.RefWSDatos.WSDatosClient(oBinding, oEndpoint);

// indicar el manipulador del evento xxxCompleted del servicio
// que será llamado al terminar de obtener la tabla de la base de datos
wsDatos.ObtenerTablaOrdersCompleted += new EventHandler<SLErrorMessageSize.RefWSDatos.ObtenerTablaOrdersCompletedEventArgs>(wsDatos_ObtenerTablaOrdersCompleted);

// llamar al método del servicio que devuelve la tabla de la base de datos
wsDatos.ObtenerTablaOrdersAsync();
}

void wsDatos_ObtenerTablaOrdersCompleted(object sender, SLErrorMessageSize.RefWSDatos.ObtenerTablaOrdersCompletedEventArgs e)
{
// asignar las filas de la tabla al DataGrid
this.grdDatos.ItemsSource = e.Result;
}
}


Al ejecutar nuevamente la aplicación ya no se producirá el error, cargándose el DataGrid con los registros de la tabla, como vemos en la siguiente figura.



El código XAML correspondiente a esta página lo vemos a continuación.


<UserControl xmlns:my=»clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data»
x:Class=»SLErrorMessageSize.Page»
xmlns=»http://schemas.microsoft.com/client/2007″
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»
Width=»500″ Height=»400″
Loaded=»UserControl_Loaded»>

<Grid x:Name=»LayoutRoot» Background=»LightCyan» >
<Grid.RowDefinitions>
<RowDefinition Height=»40″ />
<RowDefinition Height=»*» />
</Grid.RowDefinitions>

<TextBlock Grid.Row=»0″
HorizontalAlignment=»Center»
VerticalAlignment=»Center»
Text=»Tabla Orders» />

<my:DataGrid x:Name=»grdDatos»
AutoGenerateColumns=»True»
Margin=»5″
Grid.Row=»1″ />
</Grid>

</UserControl>


El código fuente del ejemplo comentado se encuentra disponible en los siguientes enlaces para C# y VB.


Espero que os resulte de utilidad.


Un saludo.

2 Comentarios

  1. rduarte

    Pero esta limitación de registros en tablas me parece algo poco usual en microsoft

  2. lmblanco

    Hola Rommy

    Yo creo que no se trata de limitar el hecho de que podamos manejar solamente las tablas pequeñas y las grandes no, sino que más bien parece una cuestión relacionada con la cantidad de datos que se transmiten a través del servicio Web. En teoría tendrías el mismo problema si intentaras enviar una cantidad de datos elevada, que no proviniera de una base de datos, pero que superara el límite por defecto establecido para el servicio según se comenta en el post.

    Un saludo.

Deja un comentario

Tema creado por Anders Norén