Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Manual Framework ASP Net
Manual Framework ASP Net
com
Eduard Toms
Le damos el nombre que queramos 1en este caso )vcFello4orld3 y el directorio donde se va a 2enerar y listos. 'n el si2uiente paso nos pre2untar6 si queremos una aplicacin J'mtpyJ o J5nternet #pplicationJ, y seleccionamos J'mptyJ. La diferencia es que en el se2undo caso ya se nos 2enera un conBunto de controladores y vistas por defecto, y ahora este cdi2o nos liar"a m6s que ayudar"a as" que vamos a obviarlo. +on J'mptyJ empe?amos con una aplicacin #$%.&'( )*+ vac"a. 'l desple2able J*ie 'n2ineJ tiene dos valores7 Da?or y #$%M. 'sto hace referencia a la tecnolo2"a con la cual se implementan las vistas. $i seleccionamos #$%M nuestras vistas ser6n archivos .aspx, mientras que si usamos Da?or nuestras vistas ser6n archivos .cshtml 1o .vbhtml si usamos *isual Casic3. Da?or es una sintaxis nueva mucho m6s compacta que #$%M y es, por tanto, la que vamos a usar nosotros.
#$%.&'( )*+ si2ue lo que se conoce como convention over confi2uration, es decir7 en lu2ar de usar archivos de confi2uracin para ciertas tareas, se usan convenciones predefinidas. N esas convenciones son re2las como las si2uientes7 /. Las vistas se ubican en la carpeta *ie 2. Los controladores son clases cuyo nombre termina en +ontroller Las carpetas que nos crea *isual $tudio por defecto son las si2uientes7 /. 2. ,. .. <. +ontent7 %ara tener contenido est6tico 1im62enes, hoBas de estilo, @3 +ontrollers7 %ara ubicar nuestros controladores )odels7 %ara ubicar las clases del modelo. $cripts7 %ara tener archivos con cdi2o Bavascript *ie s7 Donde van las vistas de la aplicacin
%odemos ver que por defecto el nombre termina con +ontroller. )odificamos para que en lu2ar de Default/+ontroller sea Fome+ontroller y le damos a #dd. 'so nos crear6 una clase Fome+ontroller en la carpeta +ontrollers con el cdi2o7
public class HomeController : Controller { //
+osas que debemos observar7 /. La clase deriva de +ontroller 2. (iene un mGtodo pEblico que devuelve un #ctionDesult y que se llama 5ndex. 'sto es una accin. +ualquier mGtodo pEblico de un controlador es por defecto una accin. 'n #$%.&'( )*+ toda peticin del nave2ador debe ser enrutada a una peticin 1mGtodo pEblico3 de un controlador. %or defecto se si2ue la convencin de que las HDLs est6n en la forma http788servidor8controlador8accion. 's decir, para invocar la accin 5ndex, del controlador Fome, usaremos la HDL7 http788servidor8Fome85ndex. -iBaos en un detalle importante7 la clase se llama Fome+ontroller pero el nombre del controlador es Fome 1sin +ontroller3
Le ponemos J5ndexJ como nombre y le damos a #dd. +on eso *isual $tudio nos habr6 2enerado un archivo 5ndex.cshtml 1situado en 8*ie s8Fome3 con el cdi2o7
#{ Vie $a%&Title ' (Index(! " )*+,Index)/*+,
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com N listosQ +on esto ya tenemos nuestra aplicacin lista. %ara probarla basta eBecutarla 1con -<3 y comprobar los resultados7
Hn Eltimo detalle7 $i os fiB6is la HDL es simplemente http788localhost, sin nada m6s y se est6 mostrando nuestra vista. LRuG ha ocurrido9 %ues que, por defecto si no se incluye controlador se asume que es JFomeJ y si no se entra accin se asume que es 5ndex. %ero si entramos la HDL completa vemos que tambiGn funciona7
%or otra parte si entramos un nombre de controlador o de accin que no existe, recibimos un .0. 1p62ina no encontrada37
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com SHn saludo a todosQ
Artculo por
Eduard Toms
#qu" se define el controlador Fome con la accin 5ndex 1recordad que las acciones son los mGtodos pEblicos que reciben las peticiones del nave2ador3. 'n esta accin establecemos las claves &ombre y ( itter del *ie Data y lue2o devolvemos la vista asociada a dicha accin. %ara mostrar los datos en la vista, simplemente usamos la propiedad *ie Data que tienen las vistas y que funciona exactamente i2ual. 'n este caso, en el cdi2o de nuestra vista 1archivo Fome.cshtml que estar"a en la carpeta Fome dentro de la carpeta *ie s3 tendr"amos al2o como7
)*+,Index)/*+, 0i nombre es #Vie 1ata2(/ombre(3 5 puedes se%uirme en )a *re6'(*ttp://t itter&com/#Vie 1ata2(T itter(3(,T itter)/a,&
-iBaos en dos cosas7 /. %ara acceder a un valor del *ie Data, simplemente usamos *ie DataTJclaveJU. 2. N muy importante7 el uso de la arroba 1V3 antes de llamar a *ie Data. 'so es parte de la sintaxis Da?or 1que veremos con detalle m6s adelante, as" que de momento no nos vamos a preocupar mucho de ella3. 'l uso de *ie Data tiene dos puntos dGbiles que deben tenerse presentes7 /. Las claves son cadenas, por lo que si nos equivocamos el compilador no puede ayudarnos. (ampoco herramientas de refactorin2 pueden darnos soporte. 2. *ie DataTJclaveJU siempre devuelve un obBect por lo que debemos ir haciendo castin2 si queremos obtener el tipo real de lo que hay almacenado. %.eB. 'n un controlador ponemos el si2uiente valor en *ie Data7
Vie 1ata2(7ec*aAlta(3 ' ne 1ateTime(+889: ;+: ;8)!
'ste valor es un Date(ime, no obstante si desde la vista queremos llamar a los mGtodos de Date(ime 1como
10
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com (oLon2Date$trin2133 deberemos hacer un castin27 Dado de alta en7 V111Date(ime3*ie DataTJ-echa#ltaJU3.(oLon2Date$trin2133 $i no hiciGramos el castin2 a Date(ime, la llamada a (oLon2Date$trin213 2enerar"a una excepcin 1aun cuando, en efecto, lo que hay en el *ie DataTJ-echa#ltaJU es un Date(ime3.
-iBaos que el cdi2o es casi i2ual al uso de *ie Data, solo que en lu2ar de hacer *ie DataTJclaveJU hacemos *ie Ca2.clave. N para recuperarlos desde una vista9 %ues i2ual que antes, podemos usar la propiedad *ie Ca27
)*+,Index+)/*+, 0i nombre es #Vie $a%&/ombre 5 puedes se%uirme en )a *re6'(*ttp://t itter&com/#Vie $a%&T itter(,T itter)/a,& )br /, 1ado de alta en: #Vie $a%&7ec*aAlta&To<on%1ate-trin%()
#qu" podemos ver la 2ran ventaBa de *ie Ca2 respecto *ie Data7 no es necesario usar castin2. -iBaos que para usar (oLon2Date$trin213 no hemos tenido necesidad de convertir el resultado devuelto por *ie Ca2.-echa#lta a Date(ime. 'sa es la 2ran ventaBa de *ie Ca2 respecto a *ie Data y es por eso que, personalmente, os recomiendo usar *ie Ca2 en lu2ar de *ie Data 1de hecho *ie Data se mantiene por compatibilidad con las versiones anteriores del frame or! de #$%.&'( )*+3. Itra ventaBa es que no usamos cadenas sino propiedades para acceder a los elementos, pero oBo, que el compilador no puede ayudaros si accedGis a una clave 1propiedad3 que no existe 1al ser las propiedades din6micas3.
public class HomeController : Controller { public ActionResult Index>() { =suario data ' ne =suario()! data&/ombre ' (Eduard Tom4s(! data&T itter ' (eiximenis(! data&Alta ' ne 1ateTime(+889: ;+: ;8)! return Vie (data)! " "
11
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com &otemos las diferencias7 'l controlador crea un obBeto de la clase Hsuario y manda ese obBeto a la vista, pas6ndolo como par6metro a la funcin *ie . LN desde la vista9 %ues usamos la propiedad )odel para acceder a dicho obBeto7
#model 0?cHello@orld&Controllers&=suario )*+,Index>)/*+, 0i nombre es #0odel&/ombre 5 puedes se%uirme en )a *re6'(*ttp://t itter&com/#0odel&T itter(,T itter)/a,& )br /, 1ado de alta en: #0odel&Alta&To<on%1ate-trin%()
-iBaos que ahora usamos )odel para acceder a los datos, en lu2ar de *ie Data o *ie Ca2. N una cosa importante7 fiBGmonos en la primera l"nea, que empie?a con Vmodel. 'sa l"nea le indica al frame or! de que tipo es el obBeto que la vista recibe del controlador 1es decir, de que tipo es la propiedad )odel3. %or supuesto este tipo debe coincidir con el obBeto que se pasa como par6metro a la funcin *ie en la accin del controlador. Hna nota7 'l uso de Vmodel es opcional, si no lo ponemos, nuestra vista puede se2uir usando la propiedad )odel, pero en este caso es de tipo dynamic. 'so tiene sus ventaBas y sus inconvenientes 1volveremos sobre ello en posteriores art"culos3. Las vistas que declaran Vmodel, se llaman vistas fuertemente tipadas. Hsar vistas fuertemente tipadas tiene una ventaBa que es que al saber *isual $tudio cual es el tipo de la propiedad )odel, nos puede proporcionar soporte de 5ntellisense. Hsar este mecanismo es la manera preferida de pasar datos desde una accin a una vista 1ya que en lu2ar de tener datos desperdi2ados en n claves los podemos tener or2ani?ados en una clase3. # las clases que se pasan desde las acciones a las vistas 1como nuestra clase Hsuario3 se les conoce tambiGn con el nombre de *ie )odels 1para distin2uirlas de las clases que conforman el )odelo del patrn )*+, ya que los *ie )odels lo Enico que hacen es contener datos que mostrar6 una vista3.
Eduard Toms
12
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com tenemos vie state ni el ciclo de vida de ebforms y adem6s es que@ son vistas de )*+, por lo que slo deben hacer tareas de presentacin3. La sintaxis que usa el motor #$%M es un poco@ eso que los an2losaBones llaman verbose, es decir que se debe escribir mucho para ciertas tareas. #s", ima2inad una p62ina que tuviese que mostrar una lista de elementos de la clase Hsuario 1la que usamos en el cap"tulo anterior3. 'l cdi2o, usando el motor de vistas #$%M queda as"7
)A# .a%e Title'(( <an%ua%e'(CB( 0aster.a%e7ile'(C/Vie s/-*ared/-ite&0aster( In*erits'(-5stem&@eb&0?c&Vie .a%e)IEnumerable)0?cHello@orld&Controllers&=suario,,( A, )asp:Content I1'(Content;( Content.laceHolderI1'(TitleContent( runat'(ser?er(, 1emoAspx )/asp:Content, )asp:Content I1'(Content+( Content.laceHolderI1'(0ainContent( runat'(ser?er(, )*+,1emoAspx)/*+, )table, )A 6oreac* (?ar item in 0odel) { A, )tr, )td, )A: item&/ombre A, )/td, )td, )A: item&T itter A, )/td, )td, )A: -trin%&7ormat(({8:%"(: item&Alta) A, )/td, )/tr, )A " A, )/table, )/asp:Content,
-iBaos en la cantidad de veces que debe usarse el ta2 XY y su pareBo YZ para indicar dnde empie?a y termina el cdi2o de servidor. D6pidamente empe?aron a sur2ir motores de vistas alternativos, reali?ados por la comunidad, con la intencin de tener sintaxis m6s claras para nuestras vistas. #l2unos eBemplos son &haml y $par!. -inalmente la versin , de #$%.&'( )*+ vino acompaada de un nuevo motor de vistas, llamado Da?or. 'so s", el motor #$%M puede se2uir siendo usado en #$%.&'( )*+,, pero honestamente no hay nin2una ra?n para hacerlo 1salvo en casos de mi2raciones, por supuesto37 Da?or es m6s claro, sencillo e intuitivo.
Sinta1is de /a0or
Lo que m6s choca de Da?or es que, a diferencia del motor #$%M donde tenemos el ta2 que inicia el cdi2o de servidor y el que lo termina, slo hay ta2 para iniciar cdi2o de servidor. 'l motor Da?or es lo suficientemente inteli2ente para saber cu6ndo termina el cdi2o de servidor, sin necesidad de que lo explicitemos. *eamos la misma vista de antes, pero ahora usando Da?or7
#model IEnumerable)0?cHello@orld&Controllers&=suario, #{ Vie $a%&Title ' (1emoRaDor(! " )*+,1emoRaDor)/*+, #6oreac* (?ar item in 0odel) { )tr, )td, #item&/ombre )/td, )td, #item&T itter )/td, )td, #-trin%&7ormat(({8:%"(: item&Alta) )/td, )/tr, " )/table,
Las diferencias saltan a la vista, Lno9 'n Da?or el s"mbolo de la arroba 1V3 marca el inicio de cdi2o de servidor. N como
13
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com comentaba antes, no hay s"mbolo para indicar que se termina el cdi2o de servidor7 el motor Da?or deduce cuando termina en base al contexto. -iBaos que para mostrar una variable de servidor 1item.&ombre p.eB.3 simplemente la precedemos de una V. -iBaos tambiGn que la llave de cierre del foreach no debe ser precedida de nin2una arroba, Da?or ya sabe que esa llave es de servidor y cierra el foreach abierto. 'l uso de la V funciona de dos maneras b6sicas7 /. Vexpresin7 Denderi?a la expresin en el nave2ador. #s" Vitem.&ombre muestra el valor de "tem.&ombre. 's decir Vexpresin equivale a XY7 expresin YZ 2. V[ cdi2o \7 %ermite eBecutar un cdi2o que no 2enera salida F()L. 's decir V[cdi2o\ equivale a XY +di2o YZ
Consideraciones a la sinta1is
Expresiones compejas +omo hemos visto el motor Da?or interpreta cuando empie?a y cuando termina el cdi2o de servidor. %ero no siempre lo consi2ue adecuadamente. %.eB, el si2uiente cdi2o Da?or7 V[ int a : /0P int b : ,P \ 'l valor de /0 ; , es7 Va;b ]enera el si2uiente F()L7 'l valor de /0 ; , es7 /0;b 's decir Da?or ha interpretado que el cdi2o de servidor terminaba al encontrar el s"mbolo de resta. 'n este caso, esa presuncin es totalmente errnea, pero por suerte podemos usar los parGntesis para que haya slo una expresin detr6s de la arroba7 'l valor de /0 ; , es7 V1a;b3 +on ese cdi2o la vista mostrar6 el valor correcto 1A3. Decordad la clave7 el motor Da?or espera una y slo una expresin detr6s de la V. %or eso debemos usar los parGntesis. "Romper" el cdigo de servidor # veces la problem6tica es Busto la contraria de la que hemos visto con las expresiones compleBas7 a veces hay cdi2o que Da?or interpreta que es de servidor pero realmente parte de ese cdi2o es F()L que debe enviarse al cliente. *eamos un eBemplo7
#6or (int i ' 8! i ) ;8! iEE) { El ?alor de i es: #i )br /, "
# priori podr"amos esperar que este cdi2o 2enerara /0 l"neas de cdi2o F()L. %ero el resultado es un error de compilacin. La ra?n es que Da?or interpreta que la l"nea J'l valor de i es7 ViJ es cdi2o de servidor. %ara JromperJ este cdi2o de servidor y que Da?or JsepaJ que realmente esto es cdi2o que debe enviarse tal cual al cliente, tenemos dos opciones7 /. 5ntercalar una etiqueta F()L. #l intercalar una etiqueta F()L Da?or Jse da cuentaJ que all" empie?a un cdi2o de cliente7
#6or (int i ' 8! i ) ;8! iEE) { )span,El ?alor de i es:)/span, #i )br /, "
2. Hsar la construccin V7 que indica expl"citamente a Da?or que lo que si2ue es cdi2o de cliente7
#6or (int i ' 8! i ) ;8! iEE) { #:El ?alor de i es: #i )br /, "
14
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com La diferencia es que en el primer caso las etiquetas se env"an al nave2adaor, mientras que en el se2undo caso no.
'n este caso Da?or interpreta que se trata de un correo electrnico, por lo que no trata la V como inicio de cdi2o de servidor. 'ste comportamiento a veces tampoco se desa. %.eB, ima2inad lo si2uiente7
)di? id'(di?F#0odel&Index(,1i? usado)/di?,
'stoy asumiendo que el *ie )odel que recibe la vista tiene una propiedad llamada 5ndex. $upon2amos que dicha propiedad 1)odel.5ndex3 vale /0. La verdad es que uno pensar"a que eso 2enerar"a el cdi2o F()L7
)di? id'(di?F;8(,1i? usado)/di?,
's decir, Da?or no ha interpretado la V como inicio de cdi2o de servidor, y eso es porque ha aplicado la excepcin de correo electrnico. La solucin pasa por usar los parGntesis7
)di? id'(di?F#(0odel&Index)(,1i? usado)/di?,
#hora Da?or sabe que )odel.5ndex es cdi2o de servidor y lo evaluar6, 2enerando el F()L que est6bamos esperando. # veces Da?or falla incluso m6s espectacularmente. Dado el si2uiente cdi2o7
#6or (int i ' 8! i )' ;! iEE) { )di? id'(di?F#i(,1i? #i)/di?, "
'n base a lo que hemos visto podr"amos esperar que 2enerase el si2uiente F()L7
)di? id'(di?F#i(,1i? 8)/di?, )di? id'(di?F#i(,1i? ;)/di?,
%ues SnoQ 'ste cdi2o hace que el motor de Da?or de un error 1(he for bloc! is missin2 a closin2 J\J character. )a!e sure you have a matchin2 J\J character for all the J[J characters ithin this bloc!, and that none of the J\J characters are bein2 interpreted as mar!up3. %or supuesto, la solucin para 2enerar el F()L que queremos pasa por usar el parGntesis i2ual que antes7
#6or (int i ' 8! i )' ;! iEE) { )di? id'(di?F#(i)(,1i? #i)/di?, "
Escapar la arroba # veces es necesario indicarle a Da?or que una arroba es eso@ una simple arroba y que no ha2a nada espec"fico. Rue no asuma nada, que no piense nada, que simplemente env"e una V al cliente. LHn eBemplo9 'l si2uiente cdi2o7
)st5le, ##media screen { bod5 { 6ontGsiDe: ;>px!" " )/st5le,
$i no us6ramos la doble arroba 1VV3, Da?or nos 2enerar"a un error, ya que Vmedia lo interpreta como Jenviar el contenido
15
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com de la variable media al clienteJ. 'n este caso al usar VV Da?or simplemente sabe que debe enviar una V al cliente y lo que el nave2ador recibe es7
)st5le, #media screen { bod5 { 6ontGsiDe: ;>px!" " )/st5le,
Conclusiones
Femos visto la sint6xis b6sica del motor de vistas Da?or, y las principales consideraciones que debemos tener presentes. &o hemos visto las capacidades adicionales de dicho motor de vistas como layouts, templates y re2iones que iremos viendo en cap"tulos posteriores. %ara finali?ar una cosilla7 #mbos motores de vistas 1#$%M y Da?or3 se pueden usar en )*+, de forma simult6nea. 'l motor de #$%.&'( )*+ intentar6 encontrar primero una vista .aspx y si no la encuentra buscar6 una vista Da?or 1.cshtml, aunque tambiGn puede ser .vbhtml si usamos *isual Casic.&'( en lu2ar de +W3. #unque por supuesto este comportamiento puede ser modificado. SHn saludo a todosQ
Artculo por
Eduard Toms
16
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com 'sos dos valores los espera el frame or! siempre, para as" poder enrutar dicha peticin hacia una accin de un controlador. %ero al mar2en de esos dos, pueden existir otros valores de ruta. N LquG hace el frame or! con el resto de valores de ruta9 %ues los 2uarda y los env"a a la accin que 2estiona la peticin. La tabla de rutas es pues la responsable de, decidir, por cada HDL, que valores de ruta, y con quG valor real, se rellenan. Decordad que controller y action son obli2atorios y que son usados por el frame or! para, precisamente, decidir quG accin de quG controlador 2estiona la peticin, de ah" que se di2a comEnmente, que la tabla de rutas mapea HDLs a acciones, aunque como hemos visto, realmente hace al2o m6s.
'ste cdi2o es el que confi2ura la tabla de rutas. 'l par6metro routes que recibe este mGtodo es la propia tabla de rutas, que est6 en la propiedad est6tica Doutes de la clase Doute(able. #nalicemos este cdi2o, y empecemos no por la primera l"nea, sino por la se2unda7 la que llama al mGtodo )apDoute. 'ste mGtodo 1que es realmente un mGtodo de extensin, aunque esto no sea relevante3 nos permite aadir una nueva entrada a la tabla de rutas de forma sumamente sencilla. 'st6 sobrecar2ado pero en este cdi2o los par6metros que recibe son7 /. 'l nombre de la ruta 1un identificador de la ruta3. 'n este caso la ruta se llama Default 2. Las HDLs que mapea esta ruta ,. Los valores por defecto de los valores de ruta, en caso de no ser encontrados en la HDL.
Patrones de -/#s
+entrGmonos un poco en se2undo par6metro. $u valor es ^[controller\8[action\8[id\_. 'so es simplemente el patrn que deben cumplir las HDLs para ser procesadas por esta ruta. Lo que est6 entre llaves es el nombre del valor de ruta que se crea. #s" pues el patrn [controller\8[action\8[id\ mapear6 cualquier HDL que estG en la forma http788servidor8xxx8yyy8???. N adem6s asi2nar6 los si2uientes valores de ruta7 /. controller : xxx 2. action : yyy ,. id : ??? %ero@ que pasa con una HDL que no ten2a el 8??? final9 Rue ocurre con una HDL http788servidor8xxx8yyy9 %ues en principio una HDL de este tipo no ser"a procesada por este patrn 1ya que el patrn pide expl"citamente que haya [controller\8[action\8[id\. %ero, para evitar que la confi2uracin de la tabla de rutas costase horrores, existe el tercer par6metro7 los valores por defecto.
17
%or lo tanto tenemos que7 'l valor de ruta ^controller_ vale ^Fome_ por defecto. 'l valor de ruta ^action_ vale ^5ndex_ por defecto 'l valor de ruta ^id_ es opcional. 's decir si no aparece no se crear6 1no existir63. &o es que val2a null, 0, cadena vac"a o cualquier otro valor vac"o, no. $implemente no se crear6.
*isto esto, ahora podemos ver que7 /. http788servidor8Coo!s8*ie 8/0 se procesar6 y los valores de ruta ser6n /. controller : Coo!s 2. action : *ie ,. id : /0 2. http788servidor8Coo!s se procesar6 y los valores de ruta ser6n /. controller : Coo!s 2. action : 5ndex 1valor por defecto3 ,. id : &o existir6 el valor de ruta ^id_ ,. http788servidor se procesar6 y los valores de ruta ser6n /. controller : Fome 1valor por defecto3 2. action : 5ndex 1valor por defecto3 ,. id : &o existir6 el valor de ruta ^id_ .. http788servidor8Coo!s8*ie 8/0820 &o ser6 procesada por la tabla de rutas. 'sta HDL no puede mapearse al patrn [controller\8[action\8[id\ $i una HDL no puede ser procesada por la tabla de rutas, el frame or! devuelve un error http .0. 1p62ina no encontrada3.
M4lti$les $atrones
La tabla de rutas se llama precisamente tabla porque puede contener varias entradas 1es decir, varios patrones de HDL, con sus par6metros por defecto, etc3. %ara aadir m6s entradas 1rutas, cada entrada se conoce como ruta3, lo m6s sencillo es aadir llamadas a )apDoute. %.eB. si quisiGramos procesar la HDL anterior http788servidor8Coo!s8*ie 8/0820 podr"amos aadir una entrada adicional7
routes&0apRoute( (1osIds(: // Route name ({controller"/{action"/{id"/{id+"( )!
#hora la HDL http788servidor8Coo!s8*ie 8/0820 ya puede ser procesada, y ser6 procesada por esa entrada nueva en la tabla de rutas. Los valores de ruta creados ser6n7 controller : Coo!s action : *ie id : /0 id2 : 20
Hn tema importante es que el orden de las rutaas en la tabla de rutas importa. %or cada HDL, el frame or! evaluar6 las distintas entradas de la tabla de rutas, una a una, en el orden en que estas se encuentren y tan buen punto una HDL pueda ser procesada, se eli2ir6 esa entrada de la tabla de rutas. %.eB. supon2amos que queremos mapear las HDLs de la forma http788servidor8*er8'du a la accin *ie del controlador %rofile con un valor de ruta llamado user cuyo valor sea lo que hay despuGs de *er 1'du en este caso3. 'so lo podemos conse2uir con una entrada en la tabla de rutas7
routes&0apRoute( (Vie .ro6ile(: // /ombre de la ruta (Ver/{aut*or"(: // =R< it* parameters ne { controller ' (.ro6ile(: action ' (Vie ( " )!
Hn detallito a tener en cuenta de esta nueva entrada es que dado que no hay lu2ar en el patrn de HDL para los valores de ruta de controller y action, al ser esos obli2atorios, deben especificarse como valores por defecto.
18
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com 'sta entrada mapea una HDL del tipo7 http788servidor8*er8'du con los valores de ruta7 controller : %rofile 1valor por defecto3 action : *ie 1valor por defecto3 author : 'du 1sacado del patrn de la HDL3
%ero, podGis comprobar que si aad"s esa l"nea despuGs del routes.)apDoute que ya hab"a, si entr6is una HDL del tipo http788servidor8*er8'du el frame or! os devolver6 un .0., incluso aunque ten26is el controlador %rofile con una accin *ie definida. L%or quG9 %ues simplemente porque la tabla de rutas se evalEa en orden. N Lpuede mapear la primera entrada 1la ruta llamada Default3 una HDL del tipo http788servidor8*er8'du9 La respuesta es que s", y los valores de ruta quedan establecidos a7 controller : *er action : 'du id : &o hay valor de ruta ^id_ 1recordad que era opcional3
%or lo tanto, a no ser que ten26is un controlador llamado *er con una accin llamada 'du 1cosa poco probable, no nos vamos a en2aar 7p3 el frame or! os devolver6 un .0.. %ara que todo funcione, la entrada ^Default_ debe estar despuGs de la nueva entrada7
public static ?oid Re%isterRoutes(RouteCollection routes) { routes&I%noreRoute(({resource"&axd/{Hpat*In6o"()! routes&0apRoute( (Vie .ro6ile(: // /ombre de la ruta (Ver/{aut*or"(: // =R< it* parameters ne { controller ' (.ro6ile(: action ' (Vie ( " )! routes&0apRoute( (1e6ault(: // Route name ({controller"/{action"/{id"(: // =R< it* parameters ne {controller ' (Home(: action ' (Index(: id ' =rl.arameter&Iptional" // .arameter de6aults )! "
'ste patrn de HDL se mapear6 a todas aquellas HDLs que ten2an la forma http788servidor8xxx.axd8yyy Dnde7 /. xxx es cualquier nombre 2. yyy es cualquier cosa, incluyendo barras separadoras 183. 'l hecho de que yyy pueda incluir barras separadoras es porque se usa la forma [`nombreavaloraruta\ 1con un asterisco3 que es lo que se conoce como catch;all y si2nifica literalmente7 captura todos los caracteres de la HDL que ven2an a partir de ahora. 's decir la HDL http788servidor8trace.axd8foo8bar8ba? ser6 enrutada por esta ruta. #l ser declarada con 52noreDoute, lo que har6 es que dicha peticin sea i2norada por #$%.&'( )*+ y ser6 procesada por al2uien m6s 1en este caso el propio motor de #$%.&'(, pero eso ya depende de cada caso3.
19
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com 'n el si2uiente art"culo vamos a ver los valores de ruta y los controladores.
Artculo por
Eduard Toms
%odemos ver como la accin *ie recibe el par6metro ^authorJ, cuyo valor ser6 valor de ruta con el mismo nombre 1autor3. 's decir, en el caso de la HDL http788servidor8*er8'du el valor del par6metro author ser6 precisamente ^'du_. 'n el caso de par6metros opcionales, la cosa es un pel"n m6s delicada. $upon2amos que tenemos la si2uiente accin7
public class HomeController : Controller { public ActionResult Index(int i) { return Vie ()! " "
$upon2amos que esta accin se ha mapeado a partir de la entrada ^Default_ de la tabla de rutas. $i entramos una url del tipo http788servidor8Fome85ndex8/0 no hay problema porque el valor de ^id_ es /0. %ero, en este caso id es un par6metro opcional, y que ocurre si entramos la HDL http788servidor8Fome85ndex9 Decordad que un par6metro opcional, si no aparece simplemente no se crea. &o es que val2a 0 ^_ o null. 's que no se crea. %or lo tanto si entramos una HDL de tipo http788servidor8Fome85ndex recibiremos un error7
'l error viene a decir que la accin espera un par6metro 1id3 pero que no hay valor de ruta del cual tomar ese par6metro. $i el par6metro aceptase null 1es decir, fuese un valor por referencia como strin23 el frame or! asi2nar"a null a ese par6metro y no se queBar"a. %ero int no acepta null, as" que el frame or! da ese error. 's normal, al principio, pensar que para solucionar esto bastar"a con aadir, un mGtodo 5ndex sin par6metros al controlador.
20
%ero si probamos esto, nos damos cuenta de que ahora nos aparece otro error distinto7
#dem6s ese error aparece indistintamente, ya sea que entremos http788servidor8Fome85ndex8/0 1con id3 o http788servidor8Fome85ndex 1sin id3. La ra?n de este error es muy simple7 una misma accin slo puede ser implementada por un solo mGtodo 1hay una excepcin a este caso que es cuando se usan verbos http distintos, pero eso lo veremos en art"culos posteriores3. 'n este caso tenemos dos mGtodos 15ndex13 y 5ndex1int33 que ambos implementan la accin 5ndex. N eso no est6 permitido. La solucin a todo ^ese l"o_ pasa por hacer una de esas dos cosas7 /. +onvertir el par6metro de la accin a al2o que acepte nulls 1p.eB. strin2 o bien int93. 2. I modificar la tabla de rutas para que el par6metro en lu2ar de ser opcional, ten2a un valor por defecto. $i optamos por el primer caso, la accin puede quedar como7
public class HomeController : Controller { public ActionResult Index(intJ id) { return Vie ()! " "
#hora, la HDL http788servidor8Fome85ndex se enruta a esta accin y como el valor de ruta id no existe, el mGtodo de accin recibir6 un null. %or otro lado la HDL http788servidor8Fome85ndex8/0 se enruta a esta misma accin y el valor de ruta id valdr6 /0 1y ese ser6 el valor del par6metro que reciba el controlador3. $i optamos por modificar la tabla de rutas, en lu2ar de declarar el valor de ruta id como opcional, dicho valor debe tener un valor por defecto7
routes&0apRoute( (1e6ault(: // Route name ({controller"/{action"/{id"(: // =R< it* parameters ne {controller ' (Home(: action ' (Index(: id ' 8" // .arameter de6aults )!
-iBaos ahora que el valor por defecto del valor de ruta id es 0. #hora la HDL http788servidor8Fome85ndex se enruta a la accin con el valor de ruta id con valor 0. N por su lado la HDL http788servidor8Fome85ndex820 se enruta a la misma accin pero con el valor de ruta id a 20. Debe notarse que en este caso no puede diferenciarse entre la url http788servidor8Fome85ndex y la url http788servidor8Fome85ndex80 1ambas HDLs tienen el valor de ruta id con valor 03. #s" terminamos este art"culo dedicado a la tabla de rutas, uno de los componentes b6sicos de #$%.&'( )*+ pero que muy poca 2ente le presta atencin al principioQ
21
Artculo por
Eduard Toms
Los nombres de los par6metros deben coincidir con los nombres de los par6metros de la querystrin2. Cien, fiBaos que dado que hemos declarado el par6metro p/ como int slo podemos pasar valores enteros, mientras que en el par6metro p2, podemos pasar cualquier cadena. $i pasamos una cadena en el par6metro p/, p.eB. la url http788host8home8index9 p/:texto>p2:otrotexto el error que recibimos es el si2uiente7
Lo que ha ocurrido es que #$%.&'( )*+ ha intentado convertir el valor de p/ 1^texto_3 a un entero. #l no poder hacerlo, internamente asi2na null al valor del par6metro p/, pero lue2o cuando debe invocar el mGtodo 5ndex y pasarle un int se encuentra que int no acepta valores null. De aqu" el error que recibimos. +omo podr"amos evitar esto9 Cueno@ una manera f6cil y sencilla es usar int9 1es decir &ullable3 en lu2ar de int para declarar el tipo de p/7
public ActionResult Index(intJ p;: strin% p+) { // Codi%o "
#hora si invocamos la url y el valor de p/ no es numGrico, nos lle2ar6 null, mientras que si el valor de p/ es numGrico recibiremos su valor. La re2la es realmente muy simple7 $i quieres que un par6metro de querystrin2 sea opcional debes usar un tipo por referencia
22
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com 1es decir una clase como strin2 o &ullable3. $i usas un tipo por valor 1como int o double3 el par6metro no puede ser opcional y adem6s el valor que se entre en la HDL debe ser convertible de cadena al tipo concreto que pon2as en el controlador.
'ste cdi2o tiene dos errores fundamentales. /. 'st6 i2norando al tabla de rutas. 'st6 2enerando las HDLs usando la convencin de +ontrolador8#ccin pero esta convencin es slo v6lida si se usa la tabla de rutas est6ndar. 'n proyectos de tamao medio es normal tener una tabla de rutas que sea totalmente personali?ada 1Sesa es una de las 2racias de #$%.&'( )*+Q3 2. 'st6 pasando los par6metros siempre en querystrin2, i2norando los valores de ruta %ara solucionar el primer punto, lo que debemos hacer es usar el Felper Hrl. Los Felpers son clases que nos proporcionan mecanismos de ayuda 1de serie vienen al2unos que iremos viendo y se pueden crear de propios3, para ayudarnos con tareas repetitivas. %ara 2enerar una HDL que respete la tabla de rutas debemos usar el mGtodo Hrl.#ction. $u firma b6sica es Hrl.#ction 1^accin_, ^controlador_3. #s" el cdi2o anterior lo podemos reescribir de la forma7
.ulsa )a *re6'(#=rl&Action((Vie (:(Home()Jpid';8(,aKuL)/a, para ?er los detalles
$i eBecutamos eso y miramos el cdi2o F()L veremos que es exactamente lo que hab"amos tecleado antes 1debido a que usamos la tabla de rutas est6ndar3. %ero si aado una entrada a la tabla de rutas, deB6ndola as"7
routes&I%noreRoute(({resource"&axd/{Hpat*In6o"()! routes&0apRoute( (Ver(: (Ver.roducto(: ne {controller ' (Home(: action ' (Vie (")! routes&0apRoute( (1e6ault(: // Route name ({controller"/{action"/{id"(: // =R< it* parameters ne { controller ' (Home(: action ' (Index(: id ' =rl.arameter&Iptional " // .arameter de6aults )!
#s" pues, siempre que necesitGis obtener una HDL desde una vista, usad Hrl.#ction@ recordad que el formato real de las HDLs depende de la tabla de rutas. #sumir que siempre estar6n en la forma 8controlador8accin es una muy mala pr6ctica 1y como dec"a antes, un error comEn al principio3.
23
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com #mbos par6metros 1de ruta y querystrin23 se mapean a par6metros de la accin del controlador. L#s" pues@ que valor recibiremos en el par6metro id de nuestra accin9 LI bien #$%.&'( )*+ 2enerar6 un error9 %ues lo que recibiremos en nuestra accin ser6 el valor del par6metro de ruta 1es decir /0, en lu2ar de 2037
-iBaos en la HDL entrada 18Fome85ndex8/09id:203 y como el valor del par6metro id es ^/0_ y no ^20_. 'so es debido a que coment6bamos antes7 #$%.&'( )*+ me?cla todos los par6metros que le lle2an antes de enla?arlos con los controladores y lo hace se2En una cierta prioridad. N los par6metros de ruta 1cuyo nombre se define en la tabla de rutas3 tienen m6s prioridad. 'so deber"a tenerlo en cuenta cuando 2enero HDLs, es decir, en este caso deber"a 2enerar HDLs usando la convencin 8controlador8accin8valoraid antes que 8controlador8accin9id:valoraid #l final eso nos implica que no deber"amos nunca 2enerar las HDLs con par6metros querystrin2 aadidos a mano. %or suerte para nosotros el helper Hrl.#ction que hemos visto antes viene de nuevo a nuestra ayuda. 'n una de sus sobrecar2as Hrl.#ction acepta un obBeto annimo cuyas propiedades son los valores a mandar al controlador. SHrl.#ction es lo suficientemente inteli2ente como para usar valores de ruta si est6n definidos y querystrin2 en caso de que noQ #s" pues si tenemos la tabla de rutas est6ndar y tenemos las si2uientes llamadas a Hrl.#ction7 Hrl /7 VHrl.#ction1J5ndexJ, JFomeJ, ne [ id : 20 \3 Hrl 27 VHrl.#ction1J5ndexJ, JFomeJ, ne [ id : 20, otroaid:,0\3 Hrl ,7 VHrl.#ction1J5ndexJ, JFomeJ, ne [otroaid:,0\3 La respuesta 2enerada por esa vista es la si2uiente7 Hrl /7 8Fome85ndex820 Hrl 27 8Fome85ndex8209otroaid:,0 Hrl ,7 89otroaid:,0 L&o es una maravilla9 Hrl.#ction sabe que id es un par6metro de ruta y nos lo coloca como tal. N sabe que otroaid no lo es y nos lo coloca usando queryastrin2. 'n este caso la accin en el controlador la tenemos definida7
public ActionResult Index(strin% id: strin% otroFid) { return Vie ()! "
-iBaos como desde el controlador recibimos de i2ual manera par6metros de ruta que par6metros que ven2an por querystrin2@ 73 'n el si2uiente art"culo del tutorial vamos a ver como mandar datos de formularios a las vistas, es decir cmo usar %I$(.
Artculo por
Eduard Toms
24
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com controlador, el uso de P3ST es el m/s com4n. Dicho r6pido y mal7 el uso de %I$( equivale al uso de formularios F()L. Di2o lo de mal porque ni los formularios son la Enica manera de enviar datos v"a %I$(, ni todos los formularios se env"an por %I$(, pero no nos vamos a centrar en estos detalles, ya que la mayor"a de formularios hoy en d"a se env"an via %I$(. La principal diferencia entre enviar datos via %I$( o via ]'( 1es decir usando la HDL, ya sea a travGs de querystrin2 que vimos en el art"culo anterior, o en valores de ruta3 es que con %I$( los datos circulan en el cuerpo de la peticin y no son visibles en la HDL.
'sta vista crea un formulario que ser6 enviado por %I$(. 'l formulario contiene7 Dos etiquetas con texto 13 Dos campos de texto 1Xinput type:_text_Z3, uno que se llama ^lo2in_ y otro llamado ^pass ord_ 1el valor de sus atributos name3. Hn botn para enviar el formulario
$i os fiB6is no hemos indicado a que HDL debe enviarse el formulario. 'so se hace a travGs del atributo action de la etiqueta XformZ. $i no aparece, el formulario se mandar6 de vuelta a la misma HDL a la que estamos. 'n el controlador 1Hsuarios+ontroller3 metemos simplemente una accin que muestre la vista7
public ActionResult /ue?o() { return Vie ()! "
Cien, si ahora con el nave2ador nos diri2imos a 8Hsuarios8&uevo nos aparecer6 la vista con el formulario. %odemos rellenar datos y pulsar enviar. #l pulsar enviar simplemente se nos mostrar6 la vista 1vac"a3 de nuevo. 'sto ocurre porque al pulsar el botn de enviar datos se env"a el formulario a la misma HDL 18Hsuarios8&uevo3 de la que venimos. %or lo tanto se invoca de nuevo la accin &uevo del controlador Hsuarios que lo Enico que hace es mostrar la vista otra ve?. #hora bien, lo que nosotros queremos es que cuando se env"e el formulario v"a %I$( podamos obtener los datos y hacer al2o con ellos. 'n definitiva queremos hacer otra cosa que no sea mostrar la vista. La verdad es que suena un poco como si quisiGramos otra accin distinta. %ero, si record6is en los inicios de este manual, diBimos que una accin slo pod"a estar implementada por un solo mGtodo en el controlador. Cueno, la verdad es que... mentimos un poquillo. La realidad es que una accin puede estar implementada por un solo mGtodo por cada verbo F((%. $i no sabes lo que son los verbos F((% no te preocupes mucho7 es la manera tGcnica de referirnos a ]'( y %I$(. #s" ]'( es un verbo F((% y %I$( es otro. Fay m6s, como F'#D, %H( y D'L'(' pero dado que no hay soporte en F()L para estos verbos no nos vamos a preocupar de ellos 1eso no si2nifica que #$%.&'( )*+ no los soporte, slo que no vamos a verlo aqu"3. %ara nosotros slo van a existir ]'( y %I$(. N volviendo a lo que dec"amos, eso si2nifica que para la misma accin 1por lo tanto, la misma
25
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com HDL3 puedo tener dos mGtodos en el controlador7 uno que se invoque a travGs de ]'( y otro que se invoque a travGs de %I$(. #s" pues podemos aadir el si2uiente mGtodo a nuestro controlador7
2Http.ost3 public ActionResult /ue?o(strin% lo%in: strin% pass ord) { // Codi%o&&& "
Ibservad como el mGtodo est6 decorado con TFttp%ostU. #l aplicar este atributo al mGtodo le estamos indicando a #$%.&'( )*+ que cuando se deba invocar la accin &uevo del controlador Hsuarios use este mGtodo si la invocacin es v"a %I$(. $i la invocacin es v"a ]'( 1p.eB. tecleando la HDL en la barra de direcciones del nave2ador3 se invocar6 el mGtodo &uevo que ya ten"amos. -iBaos pues que tenemos una manera simple y ele2ante de separar nuestro cdi2o en funcin del verbo F((% que se use. -iBGmonos ahora en los par6metros del mGtodo &uevo7 dos par6metros cuyo nombre es el mismo que los nombres de los campos del formulario. $lo con esto le basta a #$%.&'( )*+ para enla?ar los valores del formulario con los par6metros de la accin del controlador. #hora bien, ima2ina que nuestro formulario en lu2ar de tener dos campos, tiene veinte... L(e ima2inas tener que poner veinte par6metros en la accin del controlador9 %ues para evitar esto existe precisamente el model bindin2.
Model +indin*
Llamamos model bindin2 a la capacidad de #$%.&'( )*+ de crear obBetos 1de clases nuestras3 a partir de los par6metros que ven2an en la peticin. 'n nuestro caso a partir de los campos del formulario que enviamos. #s" podr"amos tener una clase Hsuario tal y como si2ue7
public class =suario { public strin% lo%in { %et! set! " public strin% pass ord { %et! set! " "
N sustituir los dos par6metros que ten"amos en la accin &uevo por un solo par6metro de tipo Hsuario7
2Http.ost3 public ActionResult /ue?o(=suario usuario) { // Codi%o&&& "
N 2racias al poder del model bindin2 recibiremos un obBeto usuario rellenado a partir de los datos del formulario. La Enica condicin es que las propiedades del obBeto se llamen i2ual que los campos del formulario. Lle2ados a este punto podr"amos validar los datos y si hay al2En error, los podemos mandar de vuelta a la vista 1Bunto con un mensaBe explicativo del error37
2Http.ost3 public ActionResult /ue?o(=suario usuario) { i6 (strin%&Is/ullIrEmpt5(usuario&lo%in) MM strin%&Is/ullIrEmpt5(usuario&pass ord)) { Vie $a%&Error ' (<o%in o pass ord no pueden estar ?acLos(! return Vie (usuario)! " // 1amos de alta el usuario en la $$11 5 redireccionamos return RedirectToAction((Home(: (Index()! "
$i el campo de lo2in o pass ord se deBa vacio, entonces aadimos un campo llamado 'rror en el *ie Ca2 y devolvemos la vista, pas6ndole como datos el obBeto usuario que hemos recibido. $i por otro lado la validacin es correcta rediri2imos el usuario a la accin 5ndex del controlador Fome. Cien, ahora vayamos a por la vista7 la idea es que si la vista recibe un obBeto de tipo Hsuario rellene los campos de texto con el valor de los campos de dicho usuario. De este modo al mandarle de vuelta el obBeto desde el controlador, el usuario ver6
26
Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com exactamente lo mismo que Gl ha enviado y slo deber6 corre2ir los errores que se le indiquen. 'l nuevo cdi2o de la vista es7
#model 0?c1atos.ost&0odels&=suario )*+,/ue?o usuario)/*+, #i6 (Nstrin%&Is/ullIrEmpt5(Vie $a%&Error)) { )di? class'(error(,#Vie $a%&Error)/di?, " )6orm met*od'(.I-T(, )label 6or'(lo%in( ,lo%in:)/label, )input t5pe'(text( name'(lo%in( ?alue'(#(0odelN'null J 0odel&lo%in : strin%&Empt5)(/, )br /, )label 6or'(pass ord(,cla?e:)/label, )input t5pe'(text( name'(pass ord( /, )br /, )input t5pe'(submit( ?alue'(en?iar(/, )/6orm,
Lo que hemos aadido respecto a la vista ori2inal es que muestre un XdivZ con el error en caso de que este exista y establecer el valor del atributo value del campo lo2in al valor del elemento recibido si existe. 'l valor del campo pass ord no lo enla?amos porque, por norma 2eneral, cuando hay un error se obli2a siempre a volver entrar el pass ord. SN listosQ $i el usuario env"a un formulario con el campo lo2in o pass ord vac"os, se le mostrar6 de nuevo los datos que hab"a entrada 1salvo el pass ord3 Bunto con el mensaBe de error. L$encillo, verdad9 %ues bien, esa manera en que hemos hecho la validacin, y la forma en como hemos modificado la vista para mostrar los datos devueltos por el controlador, aunque funcionan no son las ideales. 'n los prximos art"culos veremos dos maneras m6s ele2antes de hacerlo7 por un lado la validacin mediante Data #nnotations y por otro el uso de los helpers en las vistas... SHn saludoQ
Artculo por
Eduard Toms
27