miércoles, 27 de junio de 2012

ASP.NET 4.0 y Ajax - Desarrollar una página de búsqueda y edición dinámica de contenido usando JQuery/JSON

ASP.NET 4.0 incluye varios componentes que nos permiten trabajar con Ajax en nuestras páginas:
  • ASP.NET AJAX Server controls
  • Microsoft Ajax Library
  • Ajax Control ToolKit
  • JQuery

En este artículo nos centraremos en JQuery, desarrollaremos a modo de tutorial una búsqueda de películas que nos permita filtrar en base a un par de criterios y editar algún elemento de la lista.

JQuery es una librería javascript que nos proporciona atajos y funciones para seleccionar, manipular y animar elementos del DOM. Por otro lado incorpora métodos Ajax que facilitan este tipo de comunicación entre código cliente y servidor. JQuery está soportado por todos los navegadores actuales y es compatible con cualquier plataforma servidor que permita comunicación JSON.

En el ejemplo usaremos JQuery para mostrar el resultado de la búsqueda en una tabla HTML e implementaremos 2 llamadas a servidor intercambiando información de tipo JSON. Para más información sobre la API ver la página oficial donde se puede consultar una referencia de la librería y hacernos una idea de lo que se puede llegar a hacer con JQuery.

Usaremos Microsoft Visual Web Developer 2010 Express para crear un sitio web ASP.NET vacío y añadiremos los siguientes archivos al proyecto:
  • Web Form (Pelicula.aspx): Contendrá los filtros, la tabla de resultados y la ficha de edición.
  • Archivo JScript(JScript.js): Contendrá nuestros scripts JQuery.
  • Hoja Estilos (StyleSheet.css): Ubicaremos los estilos que se aplican en la página.
  • Clase (DataPelicula.cs): En la carpeta AppCode, crearemos objetos que simulan un acceso a datos en servidor y nuestro modelo de datos.

No me gustaría que el artículo sea más denso de lo necesario así que no dedicaremos demasiado tiempo al acceso a datos en servidor. Hay varias alternativas para acceder a datos desde nuestra página WCF, Entity Framework, ADO, LINQ, (...) aquí simularemos que nuestra página comunica con un objeto ubicado en AppCode que incluye 2 funciones públicas, una para obtener películas y la otra para actualizar una película.


Una vez tenemos el acceso a datos y nuestra clase Película que usaremos en la comunicación entre cliente y servidor, desarrollaremos la página Pelicula.aspx. La página se estructura en Búsqueda, Lista, Ficha y Scripts de Servidor.
  • Búsqueda: Añadiremos 2 labels y 2 elementos input, si usamos componentes asp sería recomendable desactivar la característica viewstate o bien usar directamente elementos input html para evitar tags innecesarios en el documento final en cliente. Es importante asignar ID a los elementos con los que trabajaremos en los scripts de cliente ya que simplificarán el trabajo posteriormente.
  • Lista: Añadiremos una tabla con una sola fila con id="Cabecera" y tantas columnas como atributos tenga nuestro objeto Película.
  • Ficha: Añadiremos labels y campos para la edición de una película. Más adelante aplicaremos un estilo a esta capa para que esté oculta por defecto y jugaremos con la característica z-index de las capas para sobreponer el div ficha al resto cuando estemos en modo edición.
  • Scripts de Servidor: JQuery mediante la función puede comunicar directamente contra Scripts ubicados en la página o contra servicios svc,asmx que estén correctamente configurados para recibir contenido JSON vía HTTP. Trataremos el tema de servicios más a fondo en futuros artículos en la sección WCF de este mismo blog!. Sigue nuestros RSS para recibir avisos con nuevas publicaciones que puedan interesarte
    En nuestro caso implementaremos las funciones de servidor en WebMethods dentro de nuestra página aspx ya que es más sencillo y óptimo en este caso. Nos podría interesar comunicar contra servicios web en una arquitectura orientada a servicios.
    Como veréis el WebMethod GetPeliculas devuelve una lista de objetos de tipo Pelicula y el UpdatePelicula recibe un objeto de tipo Pelicula.

Aquí podéis ver un ejemplo de como quedaría la página Pelicula.aspx (no añadimos código servidor en Pelicula.cs):
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Pelicula.aspx.cs" Inherits="Pelicula" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <link href="StyleSheet.css" type="text/css" rel="Stylesheet" />
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="JQueryUtils.js" type="text/javascript"></script>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="Busqueda">
        <div id="Filtros">
            <div><label for="Referencia">Nombre :</label><input type="text" id="txtNombre" /></div><br />
            <div><label for="Categoria">Categoría :</label>
            <select id="selCategoria">
                <% string[] s = Enum.GetNames(typeof(VideoClub.Data.Categoria));
                   for (int i = 0; i <= s.GetUpperBound(0); i++)
                       Response.Write(string.Format("<option>{0}</option>",s[i]));
                 %>
            </select>
            </div><br />
            <input type="button" value="Buscar" onclick="javascript:RecargarTabla();"/> 
        </div>

        <div id="Lista">
            <table id="TablaResultado" border="1" cellpadding="4" cellspacing="2">
                <tr id="Cabecera"><td>Referencia</td><td>Nombre</td><td>Categoría</td></tr>
            </table>
        </div>
    </div>
        
    <div id="Ficha" class="Ficha">
        <div><label for="Referencia">Referencia :</label><input type="text" id="Referencia"/></div><br /><br />
        <div><label for="Nombre">Nombre :</label><input type="text" id="Nombre"/></div><br /><br />
        <div><label for="Categoria">Categoría :</label><input type="text" id="Categoria"/></div><br /><br />
        <div><input type="hidden" id="Codigo" /></div>
        <br />
        <input type="button" value="Guardar" onclick="javascript:ActualizarCambios()" />
    </div>

    </form>

    <script runat="server">
        [System.Web.Services.WebMethod]
        public static List<VideoClub.Data.Pelicula> GetPeliculas(string pNombre, string pCategoria)
        {
            try
            {
                VideoClub.Data.Pelicula filter = new VideoClub.Data.Pelicula();
                filter.Categoria = pCategoria;
                filter.Nombre = pNombre;

                return new VideoClub.Data.DataPelicula().Get(filter);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        [System.Web.Services.WebMethod]
        public static void UpdatePelicula(VideoClub.Data.Pelicula pelicula) 
        {
            try 
            {
                new VideoClub.Data.DataPelicula().Update(pelicula);
            }
            catch (Exception ex) 
            {
                throw ex;
            } 
        }
    </script>
</body>
</html>
No entraré a comentar la hoja de estilos, más abajo podéis descargar el código fuente del ejemplo.

Vamos a desarrollar nuestro archivo .js donde veremos la parte de JQuery, antes de nada fijémonos en el tag head de nuestra página:
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" 
type="text/javascript"></script>
<script src="JQueryUtils.js" type="text/javascript"></script>
El primero hace referencia a la librería JQuery. Se puede referenciar una URL externa (CDN) o se puede añadir directamente el archivo .js de la librería manualmente al proyecto y referenciarlo. No notaremos diferencia en este caso pero de cara a una aplicación corporativa mejor usar URL externa porque interviene la caché y siempre es más rápida la descarga.

Nota: Al crear una nueva solución con Visual Studio, depende de la selección inicial puede ser que el proyecto incorpore por defecto la referencias a Jquery Library. En nuestro caso hemos seleccionado aplicación web vacía por tanto ha sido necesario añadir la referencia manualmente y hemos optado por hacer una referencia externa.

Lo primero crearemos una función CambiaCursor() en el .js que vincularemos posteriormente a eventos onmouseover/onmouseout de las filas que pintaremos.
function CambiaCursor() {
    if (document.body.style.cursor == 'pointer')
        document.body.style.cursor = 'default';
    else
        document.body.style.cursor = 'pointer';
}
Crearemos otra función que se encargará de buscar los valores de los filtros por el DOM y pasarlos como parámetros al script GetPeliculas que hemos creado en el lado servidor para posteriormente dibujar en nuestra tabla tantos elementos TR como elementos nos devuelva la llamada.
Explico por encima las intrucciones JQuery que usamos aquí:
  • $("#txtNombre").val(); => Selector por ID, devuelve el elemento del DOM asociado al id. Está permitido anidar y combinar instrucciones de selección, manipulación y demás con lo que si dominamos la sintaxi podemos hacer lo que imaginemos con el contenido HTML.
  • $.ajax(); => comunica con un script de servidor:
    • data: Permite pasar parámetros de entrada a la función servidor
    • succes: Permite definir un objeto data que contendrá la respuesta del servidor que en este caso devuelve una lista de objeto Película que tendrá los mismos atributos que nuestro objeto servidor gracias a la serialización JSON del contenido. Además nos permite implementar código JQuery en este caso para añadir tantos TR como filas nos haya devuelto nuestra consulta servidor.
    • error: En este caso el método servidor devolverá un objeto Exception en caso de producirse algún error en servidor. Podemos usar el método parseJSON() para deserializar la respuesta en una función cliente y mostrar la información que nos convenga por pantalla. En este caso mostramos la propiedad Message con una alerta.
function RecargarTabla() {
    //obtenemos valores de filtros
    var nombre = $("#txtNombre").val();
    var categoria = $("#selCategoria").val();
    
    //llamada al script servidor
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json",
        url: "Pelicula.aspx/GetPeliculas",
        data: "{'pNombre':'" + nombre + "','pCategoria':'" + categoria + "'}",
        success: function (data) {
            var peliculas = data.d;
            //eliminamos los  que puedan haber despues del '' (anteriores búsquedas)
            $("#Cabecera").nextUntil("table").remove();
            //guardamos respuesta en variable peliculas y añadimos una fila por elemento del array después del tag ''.
            $.each(peliculas, function (i, item) { $("#Cabecera").after("" + item.Referencia + "" + item.Nombre + "" + item.Categoria + ""); });
        },
        error: function (response) { 
            var ex = $.parseJSON(response.responseText);
            alert("Error : " + ex.Message);
            //podríamos acceder a las propiedades del objeto Exception que se ha generado en servidor (ex.StackTrace, ex.InnerException, ex.ExceptionType...) 
        } 
    });
}
La siguiente función que crearemos se lanzará al hacer clic en una fila y se encargará de recuperar los valores del TR que ha lanzado el evento, asignarlos a los campos de la ficha y mostrar con fadeIn() la capa con id="Ficha". Si nos adentramos un poco más en la referencia de JQuery seguramente veremos que hay métodos más óptimos y elegantes para obtener los valores de las celdas en este caso. Se agradecen aportaciones y comentarios!
function Editar(pID) {
    //seleccionamos la fila entera, recuperamos los valores y los asignamos a los campos de la ficha
    var selector = "#" + pID;
    $("#Codigo").val(pID);
    $.each($(selector).find("td"), function (i, celda) {
        switch (i) {
            case 0:
                $("#Referencia").val(celda.innerText);
            case 1:
                $("#Nombre").val(celda.innerText);
            case 2:
                $("#Categoria").val(celda.innerText);
        }
    });
            
    //mostramos la ficha
    $("#Ficha").fadeIn("slow"); 
}
Ya para acabar creamos ActualizarCampos que se lanzará al pulsar el evento clic del botón Guardar que hemos ubicado en la ficha de Película. La función se encarga de buscar los valores de la ficha, componer un objeto con el formato adecuado para que nuestro servidor sea capaz de parsearlo contra la clase Película, realizar la llamada Ajax al método UpdatePelicula de servidor y actualizar la tabla con los valores que han cambiado. En este método usamos JSON.stringify para aplicar la serialización JSON aunque existen alternativas para dar formato JSON a los parámetros de entrada.
function ActualizarCambios() {
    //obtener valores de la ficha
    var nombre = $("#Nombre").val();
    var categoria = $("#Categoria").val();
    var referencia = $("#Referencia").val();
    var codigo = $("#Codigo").val();

    //componer parámetro entrada UpdatePelicula en servidor
    var pelicula = { 'Codigo': codigo, 'Referencia': referencia, 'Nombre': nombre, 'Categoria': categoria };
    var Pelicula = { 'pelicula': pelicula };

    //llamada servidor
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json",
        url: "Pelicula.aspx/UpdatePelicula",
        data: JSON.stringify(Pelicula),
        success: function () {
        },
        error: function (response) {
            var ex = $.parseJSON(response.responseText);
            alert("Error : " + ex.Message);
            //podríamos acceder a las propiedades del objeto Exception que se ha generado en servidor (ex.StackTrace, ex.InnerException, ex.ExceptionType...) 
        }
    });

    //actualizar fila con los nuevos valores
    var selector = "#" + codigo;
    $(selector).replaceWith("" + referencia + "" + nombre + "" + categoria + "");

    //ocultar ficha
    $("#Ficha").fadeOut("slow"); 
}
Espero os haya resultando interesante, más adelante publicaremos alguno relacionado con otro componente Ajax de los mencionados al inicio para realizar el mismo ejemplo de película y así poder valorar un poco aspectos interesantes de cada uno de los componentes AJAX que incorpora ASP.NET 4.0.

Os dejo un enlace donde podréis descargar la solución que hemos creado en el ejemplo y os recomiendo una serie de lecturas interesantes que podéis adquirir si os interesa profundizar en el tema. Dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.

AreaTIC, ASP.NET, Ajax, JQuery, JSON   Descargar código de ejemplo



LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

sábado, 23 de junio de 2012

IIS, ASP. Habilitar rutas de acceso primarias

Nos disponemos a configurar un site ASP en un IIS 7.5 y al mostrar una página visualizamos alguno de los siguientes errores:
Server.MapPath()error 'ASP 0175 : 80004005' Caracteres no autorizados en la ruta de acceso.
Páginas Active Server error 'ASP 0131' 
Ruta de directorio primario no autorizada /XXX/XXX.asp, línea 16 
El archivo de inclusión "../XXX/XXXXX.asp" no puede utilizar ".." para indicar el directorio primario.
Causa:

Se debe a que IIS en sus versiones más recientes deshabilita por defecto la característica de configuración del site Habilitar ruta de acceso primarias basándose en motivos de seguridad. Por tanto se dará el error si usamos ".." en rutas de acceso en nuestro código y no hemos habilitado la característica Habilitar rutas de acceso primarias en la configuración de nuestro site.

Solución:

  • Adaptar nuestro código para evitar usar "..": La seguridad de nuestro servidor podría verse comprometida si usamos archivos de inclusión ya que en este caso no se garantiza que hayan accesos no deseados fuera del directorio de nuestro site.

  • Habilitar rutas de acceso primarias en la configuración del site: Si no usamos archivos de tipo "inc" en nuestro código esta sería sin duda la opción más rápida.

Nota:

En la imagen se muestra un IIS 7.5 pero hay que tener en cuenta que este escenario podría darse también en versiones anteriores de IIS. Para más información recomendamos echar un ojo a las páginas de soporte de Microsoft. Dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

miércoles, 13 de junio de 2012

Búsquedas con acentos en SQL Server

Supongamos que tenemos la siguiente tabla llamada “Persona” creada en una base de datos con intercalación (collation en inglés) sensible a acentos (AS - “Accent Sensitive”), por ejemplo, Modern_Spanish_CI_AS.

Lanzamos la siguiente consulta sobre la tabla para obtener todos los resultados posibles:

-- Obtenemos datos de Personas
SELECT * FROM Persona

Y obtenemos el conjunto de resultados que muestra la imagen.


Imaginemos ahora que queremos saber cuántas personas tenemos con el primer apellido “Pérez” así que lanzamos la siguiente consulta haciendo una búsqueda con acentos:

-- Obtenemos datos de Personas con primer apellido = Pérez
SELECT * FROM Persona WHERE Apellido1 = ‘Pérez’

La consulta nos devuelve 1 resultado pero lo que realmente queríamos es saber los Pérez/Perez/Pèrez, que la consulta nos devolviera 3 registros (podría ser el caso típico, por ejemplo, de una web con un formulario para dar de alta personas donde los usuarios los introducen con/sin acentos Pérez/Perez/Pèrez y otro formulario de búsqueda por determinados campos).

La solución pasa por tratar la intercalación como no sensible a acentos (AI – “Accent Insensitive”). Buscando por distintos foros encontrarás soluciones variadas, a continuación comentamos un par y sus pegas así como una tercera que probablemente sería lo más adecuado en este caso.


Solución 1: Cambiar la intercalación de la base de datos de AS a AI.

En nuestro caso de Modern_Spanish_CI_AS a Modern_Spanish_CI_AI. Para ello lanzaríamos la consulta:

-- Cambiar intercalación base de datos
ALTER DATABASE [nombreBaseDatos] COLLATE Modern_Spanish_CI_AI
GO

Realmente esta solución nos devolvería 3 registros en nuestra consulta anterior pero se me plantean un par de problemas:
  1. ¿Nuestro usuario SQL Server tiene los permisos necesarios para cambiar la intercalación de la la base de datos? Quizás no seamos propietario de la base de datos, administrador o tengamos un rol que permita hacerlo.
  2. ¿Sabemos cómo afecta el cambio de intercalación a las aplicaciones que acceden a esta base de datos? Quizás no sólo se esté ejecutando nuestra aplicación…

Solución 2: Cambiar la intercalación de la columna de AS a AI.

En nuestro caso lo que haríamos sería cambiar la intercalación de la columna Apellido1 ejecutando la siguiente consulta:

-- Cambiar intercalación base una columna
ALTER TABLE Persona 
ALTER COLUMN Apellido1 varchar(20) COLLATE Modern_Spanish_CI_AI
GO

Esta solución también nos devolvería 3 registros en nuestra consulta anterior pero, además de los posibles problemas de la solución anterior, si:
  1. Ejecutamos una consulta del siguiente estilo para obtener los 2 apellidos de una persona en 1 única columna.

    -- Obtener apellidos concatenados
    SELECT Apellido1 + ‘ ’ + Apellido2 AS Apellidos 
    FROM Persona
    

  2. Ejecutamos una consulta de este estilo para saber todos los apellidos que existen en la tabla.

    -- Obtener los distintos apellidos existentes
    SELECT Apellido1 FROM Persona
    UNION ALL
    SELECT Apellido2 FROM Persona
    

Obtendremos el siguiente error:
Mens. 457, Nivel 16, Estado 1, Línea 1
No se puede realizar la conversión implícita del valor varchar a varchar porque la intercalación del valor no está resuelta a causa de un conflicto de intercalación.
Esto se produce porque las columnas Apellido1 y Apellido2 tienen diferentes intercalaciones. Igual que las operaciones anteriores que producen error tampoco se puede hacer JOIN entre 2 columnas con diferente intercalación,...


Solución 3: No modificar la intercalación y especificarla en el SELECT.

Sin duda a priori es una solución más “limpia” que las anteriores, se trata de no modificar la intercalación en ningún caso y especificar en nuestra consulta la intercalación necesaria. Así, nuestra consulta original:

-- Obtenemos datos de Personas con primer apellido = Pérez
SELECT * FROM Persona WHERE Apellido1 = ‘Pérez’

Quedaría de la siguiente manera:

-- Obtenemos datos teniendo en cuenta intercalación
SELECT * FROM Persona 
WHERE Apellido1 = ‘Pérez’ COLLATE Modern_Spanish_CI_AI

La consulta anterior nos devolvería los 3 registros; de hecho, la consulta anterior nos devolverá los mismos resultados que cualquiera de estas dos:

-- Consultas equivalentes
SELECT * FROM Persona 
WHERE Apellido1 = ‘Perez’ COLLATE Modern_Spanish_CI_AI

SELECT * FROM Persona 
WHERE Apellido1 = ‘Pèrez’ COLLATE Modern_Spanish_CI_AI

Lo que significa que utilizando este método sea cual sea el valor que pongamos en el WHERE (Pérez/Perez/Pèrez) siempre nos devolverá los 3 registros, independientemente de como pongamos o no el acento. Dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

martes, 12 de junio de 2012

Login failed for user 'NT AUTHORITY \ SERVICIO LOCAL'

Analizando los logs de SQL Server te puedes encontrar con algo del tipo Login failed for user 'NT AUTHORITY\SERVICIO LOCAL'. Motivo: fallo de la validación de acceso al servidor basada en autorización de token con un error de infraestructura. Compruebe los errores anteriores. [CLIENTE: local machine] que se repite de forma periódica cada X tiempo.


¿A qué puede deberse este mensaje? Bien, lo primero que haremos es averiguar de dónde procede. Desde el mismo SSMS abrimos la herramienta SQL Profiler.


Creamos una nueva traza donde:
  1. En la pestaña Events Selection desmarcamos todos los elementos.
  2. En la parte inferior de la misma pestaña marcamos las opciones Show all events y Show all columns.
  3. En la lista de eventos, dentro del grupo Security audit seleccionamos la opción Audit Login Failed.
  4. Ejecutamos la traza.
  5. En la columna ApplicationName nos mostrará la aplicación que está generando ese mensaje en el log. En el caso que mostramos figuraba Report Server; en la columna DatabaseName encontramos el nombre de la base de datos a la que se está intentando realizar la conexión.
En este punto hemos detectado la aplicación que genera en el log de SQL Server la entrada "Login failed for user...", es cuestión de analizar qué realiza esa aplicación y el porqué del error.

En el caso que se muestra aparece ApplicationName=Report Server, el error se debía a que habíamos migrado el servidor SQL Server, se había hecho una nueva instalación que incluía SSRS (Reporting Services) cuando no era necesario y posteriormente se restauraron en el nuevo servidor las bases de datos de sistema del servidor original (master, model y msdb).

Al restaurar las 3 bases de datos anteriores se perdió el inicio de sesión NT AUTHORITY\SERVICIO LOCAL que justamente es el que tenía configurado SSRS para arrancar y el que generaba los mensajes de "Login failed for user..." en el log.


¿Cómo lo solucionamos?
  1. Abrimos en el servidor la herramienta Sql Server Configuration Manager.
  2. Seleccionamos SQL Server Reporting Services, pulsamos botón derecho del ratón y seleccionamos Stop para detener el servicio. Con esto el problema ha quedado resuelto, ya no se generan más entradas en el log pero… nos queda un último paso.
  3. Una vez detenido el servicio volvemos a pulsar botón derecho del ratón sobre SQL Server Reporting Services, y seleccionamos Properties, vamos a la pestaña Service y cambiamos la propiedad Start Mode de Automatic a Manual; de esta manera cuando se reinicie el servidor no volverá a arrancarse el servicio de forma automática y así evitamos que SSRS vuelva a originar el mensaje en el log de SQL Server.
  4. Aceptamos en el cambio en la pantalla de Propiedades y cerramos la herramienta Sql Server Configuration Manager, el problema ha quedado solucionado.
Es un buen caso para ver cómo con la herramienta SQL Profiler podemos analizar de dónde vienen ciertas entradas del log de SQL Server.

Dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

lunes, 11 de junio de 2012

El indicador de seguimiento 4616 no está establecido en el servidor de base de datos.

Al entrar en MS Dynamics NAV puede aparecerte el siguiente mensaje de error:


Una solución rápida es ejecutar la siguiente consulta en SQL Server Management Studio para activar el

indicador de seguimiento 4616

que nos indica el mensaje:
-- Establecemos indicador de seguimiento
DBCC TRACEON(4616,-1)
GO
Una vez ejecutada la consulta el error no vuelve a aparecer y los usuarios acceden sin problemas… hasta que reiniciemos el servicio de SQL Server sobre el que funciona MS Dynamics NAV que hará que nos vuelva a aparecer el mensaje. Por tanto, lo que hemos de hacer es activar el indicador con el inicio del servicio. Para ello realizaremos lo siguiente:
  1. Abrimos en el servidor la herramienta Sql Server Configuration Manager.
  2. Seleccionamos el servicio SQL Server, pulsamos botón derecho y seleccionamos Propiedades.
  3. Vamos a la pestaña Opciones avanzadas y buscamos la opción Parámetros de inicio.
  4. Al final del valor de la opción indicada añadiremos

    ;-T4616

    . La próxima vez que se reinicie el servicio se hará con el

    indicador de seguimiento 4616 activado.


Un par de temas más a tener en cuenta:
  1. ¿Qué son los indicadores de seguimiento?
    Son marcas que sirven para activar/desactivar comportamientos específicos de un servidor SQL Server. Es posible que en próximas versiones de SQL Server los indicadores de seguimiento no estén soportados. Podemos obtener más información sobre los indicadores de seguimiento en el siguiente link.

    http://msdn.microsoft.com/es-es/library/ms188396.aspx

  2. En algunos foros se comenta que no es necesario activar el

    indicador de seguimiento 4616

    para las versiones MS Dynamics NAV 5.0 SP1 o MS Dynamics NAV 2009 SP1. Sinceramente, no lo he podido comprobar, os dejo el link a uno de los foros donde lo comentaba.

    http://blogs.msdn.com/b/nav/archive/2010/02/11/sql-server-trace-flag-4616-no-longer-required-for-dynamics-nav-2009-sp1.aspx

Espero que os haya servido de ayuda, a mí me permitió solucionar el problema de forma definitiva. Dentro de

areaTIC

puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET