sábado, 16 de abril de 2011 a las 18:12hs por Gustavo Cantero (The Wolf)
Cada vez es más frecuente ver aplicaciones que utilizan AJAX para obtener información de algún proceso del servidor y con ella actualizar la página. Con .NET esto se puede hacer fácilmente utilizando el ScriptManager para llamar a servicios web, pero muchas veces no queremos agregar tanta complejidad porque simplemente necesitamos llamar a un método que nos devuelva, por ejemplo, la hora de nuestro server.
Para hacer lo mencionado podemos crear un WebMethod en nuestra página y llamarlo utilizando jQuery (casi todos los sitios web actualmente utilizan jQuery para alguna tarea).
Vamos a explicar cómo hacerlo creando un ejemplo sencillo, en el cual vamos a tomar dos números ingresados por el usuario en campos de texto, los vamos a enviar al WebMethod donde vamos a sumarlo (esta tarea se va a realizar en el servidor) y luego devolveremos el resultado a la página.
En el código de nuestra página vamos a agregar el método pero teniendo en cuenta que debemos agregarle el atributo “WebMethod” como muestro a continuación con C#:
using System; using System.Web.Services; namespace Ejemplo { public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } [WebMethod] public static double Sumar(double Valor1, double Valor2) { return Valor1 + Valor2; } } }
Si prefieren hacerlo con Visual Basic (VB.NET) es muy parecido:
Imports System.Web.Services Public Class Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load End Sub <WebMethod> Public Shared Function Sumar(Valor1 As Double, Valor2 As Double) As Double Return Valor1 + Valor2 End Function End Class
Pero para que este método pueda ser llamado desde una página también debemos agregar en el web.config la referencia al HttpModule que maneja estas llamadas:
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpModules> <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules> </system.web> </configuration>
Con esto ya terminamos de hacer todo lo necesario en .NET para que nuestros scripts puedan utilizar este método. Ahora debemos agregar la llamada desde nuestra página. Para hacerlo debemos agregar el archivo de JavaScript con la librería de jQuery a nuestra página. Podemos descargar esta librería y “apuntar” a este archivo o simplemente podemos hacer que nuestra página la descargue de los servidores de Microsoft, Google o jQuery (en el ejemplo hago esto último). En la página http://docs.jquery.com/Downloading_jQuery podemos ver las distintas opciones de descarga o utilización de los CDN (Content Delivery Network) que podemos utilizar.
Entonces, en nuestra página de ejemplo, agregamos el siguiente elemento de HTML para que obtenga la librería del CDN de Microsoft:
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.2.min.js" type="text/javascript"></script>
Ahora que tenemos la librería podemos llamar a nuestro método desde nuestra página de la siguiente manera:
$.ajax({ //Tipo de llamada type: "POST", //Dirección del WebMethod, o sea, Página.aspx/Método url: "Default.aspx/Sumar", //Parámetros para pasarle al método data: '{Valor1: 22, Valor2: 33}', //Tipo de contenido contentType: "application/json; charset=utf-8", //Tipo de datos dataType: "json", //Función a la cual llamar cuando se pudo llamar satisfactoriamente al método success: resultado, //Función a la cual llamar cuando se producen errores error: errores });
A continuación les dejo el HTML completo de nuestra página de ejemplo, donde toma los dos números, los envía a nuestro método y luego pone el resultado en otro campo de texto:
<!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"> <title></title> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $('#btnSumar').click(function () { var num1 = $('#num1').val(); //Obtenemos el primer número var num2 = $('#num2').val(); //Obtenemos el segundo número $.ajax({ type: "POST", url: "Default.aspx/Sumar", data: '{Valor1: ' + num1 + ', Valor2: ' + num2 + '}', contentType: "application/json; charset=utf-8", dataType: "json", success: resultado, error: errores }); }); }); function resultado(msg) { //msg.d tiene el resultado devuelto por el método $('#num3').val(msg.d); } function errores(msg) { //msg.responseText tiene el mensaje de error enviado por el servidor alert('Error: ' + msg.responseText); } </script> </head> <body> <form id="form1" runat="server"> <div> <br /> <br /> <br /> <input type="text" id="num1" /> + <input type="text" id="num2" /> <input type="button" value="=" id="btnSumar" /> <input type="text" id="num3" disabled /> </div> </form> </body> </html>
Como verán utilizar WebMethods de ASP.NET desde jQuery es muy sencillo y útil, y puede servirnos en muchas tareas, por ejemplo, en formularios de envío de mail para no tener que recargar la página, para crear campos con “autocomplete”, para obtener información actualizada por otros usuarios sin necesidad de refrescar la página (como hace Facebook), etc.
También les dejo un proyecto con el ejemplo anterior funcionando:
Espero que les sea de utilidad.
Suerte!
Categoria AJAX, ASP.NET, jQuery | Etiquetas: AJAX, WebMethod
Hola, excelente página.
Intente desarrollar el efecto de Autocompletar tomando como base tu ejemplo y agregandole una consula a una BD SQL, pero en la lista me devuelve «Undefined», es decir, si encuentra 3 coincidencias ne la base de datos con la palabra escrita en el cuadro de autocompletar en la lista me aparece varias veces «Undefined», podiras ayudarme si te envio el ejemplo???
Si, no hay problema, copiá tu código y lo vemos.
Saludos!
«namespace Ejemplo
{
public partial class Materiales : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static List ObtenerMateriales(string Palabra)
{
var dc = new LinqMaterialesDataContext();
var Resultado = from e in dc.T_AnexoC5
where e.Concepto.Contains(Palabra)
select new ListC5 {id=e.Partida, value = e.Concepto };
return Resultado.ToList ();
}
public class ListC5
{
public string id { get; set; }
public string value { get; set; }
}
}
}»
Hola, Ernesto, perdón por la demora en responder.
Yo creo que el problema es porque estás devolviendo un objeto «List», el cual no existe en JavaScript.
Te recomiendo que lo pases a un vector, como te muestro a continuación:
Suerte!
«la parte del Jquerye es esta
$(function () {
$(«#TextBox2»).autocomplete({
source: function (request, response) {
$.ajax({
url: «Materiales.aspx/ObtenerMateriales»,
data: «{ ‘Palabra’: ‘» + request.term + «‘ }»,
dataType: «json»,
type: «POST»,
contentType: «application/json; charset=utf-8»,
dataFilter: function (data) { return data; },
success: function (data) {
response($.map(data.d, function (item) {
return {
value: item.Email
}
}))
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
},
minLength: 2
});
});
«
Amigo, solo quisiera hacerle una consulta con respecto a seguridad. Es esto sugúro para por ejemplo implementar este código en un Inicio de sesión? Que pasa si alguien hace ver codigo? mostraría el password escrito por el usuario, ¿no?
Desde ya muchas gracias.
El código no contiene el password, por lo cual, es seguro.
De todas formas siempre está la posibilidad de que alguien snifee la red y vea tu contraseña, para lo cual, lo mejor sería implementar https para encriptar tus comunicaciones entre el javascript (que es el que va a enviar tu password) y el servidor (que es el que va a validar el password).
Saludos.
Gracias Gustavito. Gracias por responder. De todas maneras puedo encriptarla yo y enviar los datos encriptados para no usar https, verdad?
Desde ya mil gracias.
Un gran abrazo desde Argentina.
El problema es que cualquier podría ver la forma en que encriptás los datos revisando tus scripts y luego desencriptar lo que snifee.
Para evitar esto deberías hacer un método de encriptación asimétrico. En este artículo tenés explico los distintos métodos de cifrado y otros conceptos de criptografía: Conceptos de Certificado Digital y Firma Digital.
Otra posibilidad que se me acaba de ocurrir es que calcules el hash de la contraseña y que sea esto lo que enviás al servidor (no la contraseña), para luego compararlo con el hash de la contraseña guardada en la base de datos. En este artículo explico como calcular el hash en .NET: Como calcular el Hash de un vector de bytes o un string y en esta página hay un algoritmo para calcular el hash MD5 desde javascript: JavaScript MD5.
Suerte!
NO me funciono el codigo.
No hace nada.
Estoy utilizando Master page y el codigo que pusiste arriba lo estoy usando en el default y no en el master page.
que puede ser.
Hola, Jose. ¿No te da ningún error? ¿Modificaste el web.config?
Saludos.
muchas gracias por el ejemplo en verdad me sirvio para lo que tenia que hacer solo una duda en el web.config configure el httpModules y generaba un error, pero no lo utilice en el web.config y igual fuciono perfecto
Buen día!
Tu sugerencia es útil y sencilla, pero ¿es posible evitar que el método «Sumar» sea static?
Gracias!
No se puede, porque sino deberíamos instanciar la clase Page.
Saludos.
Hola Gustavo: muy bueno tu blog. Te cuento que estoy desarrollando un Framework para crear aplicaciones sin PostBacks, en donde hago uso y abuso de los WebMethods. Me parece que es la solución cuando las aplicaciones se tornan mas y mas ricas en posibilidades.
Te invito a participar de esta experiencia, que si no me equivoco, te va a interesar.
Te mando un abrazo
Muchas gracias y felicitaciones por tu trabajo, es muy interesante!!!!!
Ya compartimos el link de tu blog en nuestra fan page de Facebook y en nuestro Twitter.
Suerte!
Muy bueno y bien explicado.. Lo he probado con datos de tipo string y me da error. Como lo puedo solucionar
Fijate que en la columan 14 está armando un JSON como si fueran números, si le ponés string debería tener comillas.
Prueba cambiando la linea por esto:
Suerte!
Ok. Funciona perfecto, muchas gracias!! Saludos
Me alegro.
Suerte!
Hola, de nuevo por el blog, me gustaria consultar si el parametro que resive el
evento success que llama a function resultado debe ser siempre un tipo primitivo
o puede ser tambien un objeto o lista?
El valor que recibe la función definida en la propiedad «sucess», en nuestro ejemplo la función de javascript «resultado», puede recibir un valor complejo. Para esto desde .NET deberías devolver una estructura o clase y el motor te lo convierte en una estructura JSON.
Aprovecho para recomendarte que, si necesitás devolver datos complejos, crees tus propias clases con la mínima información a devolver, ya que esta info va a viajar por internet y puede generar demoras en la ejecución.
Saludos.
Hola Gustavo, con respecto a llamar metodos con jQuery, tengo una pregunta sobre algo relacionado, Como realizar post basados en Cross Domain de Manera Syncrona, algo que pueda funcionar tanto en iExplorer 7 o superiores, Firefox y Chrome! Se que iexplorer tiene el objeto XDomainRequest, que aparece a partir de la version 8, jQuery tiene algo como jsonp, con la particularidad de que son procesos asyncronos!
Gracias y Saludos!
Ya hice un par de cosas con JSONP y funcionaba bien, pero nunca de forma sincrónica. Creo que lo mejor sería que hagas un diálogo modal para esperar a que termine llamada.
Saludos.
Hola, me ha servido mucho tu ejemplo, pero para pasar los parámetros que recibe el [webmethod] a otra función dentro del mismo aspx.cs me marca el error «Referencia a objeto no establecida como instancia de un objeto.» justo en la línea en la que mando a llamar la otra función con los parámetros, la pregunta es se tiene que instanciar desde el page o cómo se instancia?
Este es el código del webmethod
[WebMethod]
public static decimal Sumar(decimal Valor0, decimal Valor1, decimal Valor2,decimal Valor3,decimal Valor4,decimal Valor5,decimal Valor6,decimal Valor7, decimal Valor8, decimal Valor9,decimal Valor10, decimal Valor11, decimal Valor12, decimal Valor13, decimal Valor14, decimal Valor15, decimal Valor16, decimal Valor17, decimal Valor18, decimal Valor19)
{
int modificado = 0;
modificado = (new busquedaIni()).depurarControlDoctos(Valor0, Valor1, Valor2, Valor3, Valor4, Valor5, Valor6, Valor7, Valor8, Valor9, Valor10, Valor11, Valor12, Valor13, Valor14, Valor15, Valor16, Valor17, Valor18, Valor19);
return Valor1 + Valor2;
}
y la función depurarControlDoctos
public partial class busquedaIni : System.Web.UI.Page
{
private int depurarControlDoctos(decimal Valor0, decimal Valor1, decimal Valor2,decimal Valor3,decimal Valor4,decimal Valor5,decimal Valor6,decimal Valor7, decimal Valor8, decimal Valor9,decimal Valor10, decimal Valor11, decimal Valor12, decimal Valor13, decimal Valor14, decimal Valor15, decimal Valor16, decimal Valor17, decimal Valor18, decimal Valor19)
{
decimal[] valores;
valores = new decimal[20]{Valor0, Valor1, Valor2, Valor3, Valor4, Valor5, Valor6, Valor7, Valor8, Valor9, Valor10, Valor11, Valor12, Valor13, Valor14, Valor15, Valor16, Valor17, Valor18, Valor19};
string ControlDoc = «»;
int indiceCtrlDoc = gvControlDoctos.Rows.Count;
int modificado;
for (int i = 0; i < indiceCtrlDoc; i++)
{
ControlDoc = gvControlDoctos.DataKeys[i].Values[2].ToString();
if (!(valores[i].ToString().Equals(ControlDoc)) && !(valores[i].ToString().Equals('0')))
{
gvControlDoctos.DataKeys[i].Values[2] = valores[i];
decimal estatusdoc_id, docto_id;
estatusdoc_id = Convert.ToDecimal(gvControlDoctos.DataKeys[i].Values[2]);
docto_id = Convert.ToDecimal(gvControlDoctos.DataKeys[i].Values[0]);
string matricula = "";
matricula = gvBusquedaInicial.SelectedDataKey.Values[0].ToString();
modificado = (new negocioControlDoctos()).modificaCtrlDoctos(matricula, docto_id, estatusdoc_id);
}
}
return Convert.ToInt32(Valor1);
}
}
bueno también hay otras cosas pero según yo éstas son las importantes.
De antemano gracias por la atención prestada.
Janet, el problema es que los webmethods son métodos estáticos que se ejecutan de forma «aislada» del ciclo de vida de la página, por lo cual, la misma no está instanciada ni se puede acceder a ningún control de ésta del lado del servidor.
Lo que puedes hacer es leer el valor de los controles que necesites en el cliente usando javascript o alguna librería como jQuery y enviar estos valores como parámetros al webmethod.
Suerte!
Hola, una pregunta: Tengo una MasterPage, en la cual en la parte del html mando a llamar el metodo $.ajax , pero si redirecciono un WebForm (Ejemplo Response.Redirect(Inicio/Presentacion.aspx) ) que no este al nivel de la MasterPage nunca se ejecuta la funcion estatica con el atributo “WebMethod”, en cambio si redirecciono un WebForm que este al mismo nivel (directorio) de la MasterPage (Ejemplo Response.Redirect(Presentacion.aspx) ) la funcion si se ejecuta
Jandy, no entiendo la consulta. ¿Podrás poner una parte del código?
Saludos.
muchas gracias por tu aporte, tenia dias buscando la solucion.
ahora requiero pasar un arreglo, pero me marca error
Error: {«Message»:»Se ha pasado un objeto no válido. Se esperaba \u0027:\u0027 o \u0027}\u0027. (28): {IdInvestigaciones: 281,283, IdGestor: reerer}
, copio mi codigo:
js.
var borrar = [281,283];
$.ajax({
type: «POST»,
url: «Asignar.aspx/setGestorInvestigacion»,
data: ‘{IdInvestigaciones: ‘ + borrar + ‘, IdGestor: ‘ + «reerer» + ‘}’,
contentType: «application/json; charset=utf-8»,
dataType: «json»,
success: resultado,
error: errores
});
c#
public static int setGestorInvestigacion(int[] idInvestigaciones, string codigoGestor)
{
gracias por su ayuda.
Hola, Rafael.
Para que funcione, como le estás especificando que lo que envías es json, deberías formatear el contenido como json.
Creo que con algo como esto te debería funcionar:
Suerte!
gracias por tu ayuda…
ahora me envia el error:
Error: {«Message»:»Llamada al servicio Web no válida. Falta un valor para el parámetro: \u0027idInvestigaciones\u0027.»,»StackTrace»:» en System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)\r\n
no logro comprender que estructura o tipo de datos recibo en el webmethod de C#.
Me parece que el problema es porque puse el nombre de las propiedades del JSON en mayúsculas, pero en C# las espera con minúsculas.
Prueba con esto:
Por favor comentame si te funcionó.
Suerte!
Me olvidé de responderte la duda que tenias: lo que hace este código es tomar cada propiedad del JSON (lo que guardé en la variable «datos») y la pasa como un parámetro en la llamada al método de C#, por eso fijate que la variable tiene estos miembros:
que se tienen que llamar exáctamente igual a los parámetros que recibe C#:
Suerte!
muchas gracias …
funciono perfecto…
muy buen aporte, justo lo que necesitaba.
Me alegro!
Saludos.
Muy buen ejemplo,, gracias me sirvio de ayuda!!
Me alegro.
Suerte!
Hola y gracias por el tutorial….nose si me podras ayudar con un problema con dialog. Trato de llamar una pagina en un dialogo.
$(function () {
var $dialogo = $(»)
.load(«buscar.aspx»)
.dialog({
title: «Hola»,
autoOpen: false,
width: 500,
height: 500,
draggable: false,
resizable: false,
close:false
});
$(«#llamar»).click(function () {
$dialogo.dialog(«open»);
});
});
el problema es que se cierra de inmediato.como podria hacerlo para que no se cerrara.
Creo que es porque está vacío el selector, probá con algo así:
Gracias man. Como me quedo.
function Ventana() {
var $dialog = $(»)
.html(»)
.dialog({
title: «Busqueda»,
autoOpen: false,
modal: false,
height: 300,
width: 300,
draggable: false,
resizable: false
});
$dialog.dialog(«open»);
};
lo malo es que lo hago atravez de un Buscar.
no se porque cuando lo hago con un boton no quiere funcionar. peo bueno.
Muchas gracias por la ayuda.
Hola Gustavo, acabo de utilizar tu código para verificar si existe un ID de un usuario en mi BD, obvio modificándolo un poco, y funciona perfecto!! Pero, quisiera hacer que hiciera la validación sin tener que darle clic a un botón, no sé, tal vez usando un onchange, pero no he podido hacerlo, si tienes alguna idea sobre como poder hacerlo utilizando el mismo código que tienes, solo quitando el botón jeje, me seria de mucha ayuda. Gracias de antemano y excelente aporte para los que no sabemos mucho de estos temas!!
Calculo que para eso podrías hacer que en el evento keyPress se llame al método setTimeout para que a los 2 segundos de pulsada la tecla llame a la verificación. Tené en cuenta que deberías guardar el id que te devuelve el setTimeout para que, cuando pulses de nuevo una tecla, llames al método clearTimeout con este identificador para que no se llame a la validación por cada tecla pulsada, sino sólo por la última.
Debería ser algo así:
Después contame si te sirvió.
Saludos.
Hola soy nueva en esto de Ext Js 3 y estoy teniendo algunos problemas para validar no se si alguien pueda ayudarme tengo que validar datos del lado de mi js y de mi método JSON pero al realizarlo en ambos me marca error que podria hacer en este caso
gracias
mis controles son de asp como lo hago no me funciona? ayuda
¿Es necesario que un método Web (WebMethod) le regrese algo al cliente o no?. Es decir ¿Puedo crear un método Web con la siguiente firma:
[WebMethod]
public static void MiMetodoWeb()?
Hola, Luis.
Si, es necesario que devuelve algo, aunque sea un string null.
Saludos.
interesante, ya lo apliqué y funciona de maravilla, pero, como podría hacerle para que, en vez de llamar un método del webform.aspx llame a un método de una clase.cs? ya lo intenté de mil y un maneras y no logro solucionarlos.
Saludos.
Hola, Alexis.
Lo que pedís no se puede hacer porque una clase «común» no tiene un punto de entrada desde Internet, en caso las páginas web, al igual que los servicios web, handlers, etc., si reciben las llamadas desde el IIS.
Si el problema es que querés centralizar tus métodos tal vez podrías hacer un servicio WCF (el cual no tiene interfaz HTML como las páginas) para que responda a los llamados recibidos desde tu página.
Otra opción (aunque me gusta más la opción anterior) es que crees un Handler que en lugar de devolver HTML devuelva un JSON.
Espero te sirva.
Saludos.
Necesito ayuda, acabo de comenzar a programar javascript, ajax etc, tengo una clase llamada calcular en mi codigo de aspx.cs que contiene un metodo que calcula unos valores
pero necesito mostrar ese resultado en un label el cual el codigo lo tengo en mi pagina de javascript,