Archivos en la Categoría: .NET

I came to my attention today that quite a few developers don’t know about the HttpUtility class (in the System.Web namespace). Its a handy little utility that has static methods that provide all of the little encoding and decoding functions for html and url strings jusk like an instance of the HttpServerUtility class (Server.UrlEncode for example), but is available outside of a web context.

Si estas buscando usar UrlEncode() desde alguna clase tuya, que no esta dentro de un proyecto web, te vas a encontrar conque el objeto Server no esta disponible. Por suerte, existe este objetito HttpUtility que tiene las funciones como static, y las vas a poder usar :)

Si les da este error cuando tratan de navegar un site hecho en ASP.net 2, con Visual Studio 2005, sigan estos pasos para solucionarlo:

  1. Si tenes el VS abierto, cerralo
  2. Anda a la carpeta de archivos temporales de ASP.NET:  <Windows dir>\Microsoft.Net\Framework\v2.0<nro. del framework>\Temporary ASPNET pages
  3. Borra la carpeta de tu aplicacion (o todas, si tenes ganas — son temporales)
  4. Corre iisreset para reiniciar el IIS
  5. Abri un browser y navega tu sitio
  6. Ahora abri el Visual Studio.

Parece ser un problema con los permisos en algunas carpetas internas.

Si ves que tu log de errores se llena de errores del tipo Padding is invalid and cannot be removed, con una excepcion parecida a esta:
System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Boolean useValidationSymAlgo)
at System.Web.UI.Page.DecryptString(String s)
at System.Web.Handlers.AssemblyResourceLoader.System.Web.IHttpHandler.ProcessRequest(HttpContext context)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Lo que tenes que hacer es agregar al robots.txt del raiz de tu sitio que NO se indexen los archivos .axd.

El culpable es Google Bot, que al seguir todos los links de la pagina, tambien indexa el Scriptmanager.axd, generando las excepciones.

User-agent: *
Disallow: /*.axd$

Con eso hacemos que los buscadores ignoren totalmente los archivos .axd, que realmente no tienen nada importante.

Claro que Uds. se preguntan que corcho tiene que ver una libreria de JS contra un lenguaje server side? Bueno, hay un motivo :) EN realidad esto apunta hacia el uso de los metodos AJAX de la JQuery.

Como algunos saben, ASP.NET es un motor montado “sobre” el framework de .NET. Como motor, tiene muchas cosas (manejo de sesiones, Requests, themes,  skins, autenticacion, etc etc) que en realidad se ejecutan cada vez que ejecutamos una pagina ASPX. 

Entonces, supongamos que nosotros queremos hacer un metodo que nos devuelva un objeto JSON 

{"name":"Pepe","surname":"Gomez","message":"Hi world"}

Para hacer eso, tranquilamente podriamos hacer una pagina .ASPX que tuviera el Response.Write que necesitamos, no hay nada malo en hacer eso. Y despues con la JQuery tomarlo. Pero que pasa? Usando un ASPX estamos probablemente usando modulos que no necesitamos para algo tan sencillo como ir al server y volver.

Para eso, se recomienda usar los User Handled Modules (.ashx). Estos archivos no tienen toda la bocha de modulos que se cargan por default en los ASPx, y sin embargo, se puede usar todo el framework como si fuera una clase en C#/VB.net. La parte “mala” es que, al no tener “dos capas” como tiene ASP.NET (una capa de presentacion y la capa de code-behind), tenemos que “escupir” el HTML o los objetos usando Response.Write.

using System;
using System.Web;
using System.Web.SessionState;

public class Handler : IHttpHandler , IReadOnlySessionState{

    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/html";
        context.Response.Write("Hello World");
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

Entonces nuestro codigo quedaria algo asi:

Pagina Nombre.aspx

<script>
function actualizar() {
 $.getJSON("miHandler.ashx",
        function(data){
          $("#prueba").html ( data.name + " - " + data.message);
       });
}
</script>
<input onclick="actualizar()" type="button" value="Voy a ejecutar eso" />

Handler miHandler.ashx

using System;
using System.Web;
using System.Web.SessionState;

public class Handler : IHttpHandler , IReadOnlySessionState{

    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        context.Response.Write(" {\"name\":\"Pepe\",\"surname\":\"Gomez\",\"message\":\"Hi world\"} ");
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

Si necesitan (por algun motivo) acceder a la sesion dentro del Generic Handler, no se olviden de implementar la interface IReadOnlySessionState, de otra forma, el objecto context.Session es null. Si necesitan acceso de lectura y escritura, deberian implementar IRequiresSessionState .

Y para acceder al Request (para recuperar parámetros por ej) pueden usar context.Request

Mas informacion

Ciclo de vida de ASP.net

Les dejo un grafico del ciclo de vida de ASP.net 2. Ahora entiendo porque no se me ejecutaba ayer el Page_PreInit en el UserControl… es porque no ta :D

Si les da este chotisimo error, simplemente saquen cualquier tag de ASP.net que tenga que ver con los extenders del AjaxToolkit, y ponganlo cerca del control que quieren laburar. Por ejemplo, yo tenía un ajaxToolkit:UpdatePanelAnimationExtender, que referenciaba a un asp:UpdatePanel. Tenía los extenders arriba de todo, y el updatePanel más abajo. Cuando quise encerrar todo en un nuevo updatePanel, explotó todo y me daba ese error inendentible. La solución fue poner todo el código del extender justo antes del UpdatePanel, o sea, quedó así

<ajaxToolkit:UpdatePanelAnimationExtender ID="updAnimationExtender" runat="server" TargetControlID="upnlUsersList">
     <Animations>
        <OnUpdated>
            <Parallel Duration="0.5" Fps="30">
                <FadeIn />
            </Parallel>
        </OnUpdated>
    </Animations>
</ajaxToolkit:UpdatePanelAnimationExtender>							

<asp:UpdatePanel ID="upnlUsersList" runat="server" UpdateMode="Conditional">
	<ContentTemplate>
	...
	</ContentTemplate>
</asp:UpdatePanel>

Y listo! Funciona todo perfecto.

Esta discusión la tuve cuando entré a trabajar a la empresa donde estoy ahora.

Donde estaba antes, laburabamos con 3 o 4 capas de componentes:

  • Presentación (HTML o WinForms)
  • Facade (solo si la aplicación era ENORME)
  • Lógica
  • DB
La presentación eran los ASPx y JS que fueran necesarios tener. La capa de Facade se usaba para hacer transformaciones, o tocar, si era necesario, la información que llegaba desde la capa de Presentación para pasar a la capa de Lógica. La de Lógica se encargaba de cualquier transformación a nivel lógico de la información, y por último, la capa de DataBaseAccess, que se comunicaba contra las Application Data Blocks de Microsoft (en esa época se llamaban distinto, pero whatever, era el objeto que en realidad tiraba la info a la DB, y se encargaba de las transacciones, etc).
Usando un ejemplo gráfico, quedaría de esta forma (no pongo facade aca, y es algo muy basico).
- La página default.aspx es la presentación
- La clase user.cs se encarga de verificar y transformar la información
- La clase userDB.cs se engarga de preparar la info para pasarle a las DataBlock
- La DataBlock ejecuta y devuelve True si todo salió bien
Sin embargo, aca en esta empresa sacan una capa (la de lógica) porque dicen que pasar entre capas tiene “mas peso”…
Alguien sabe si esto es verdad? O es un capricho? O sea, entiendo que una llamada a una capa mas pueden ser algunos milisegundos, pero a mi gusto, queda mucho mas prolijo de la primer manera.

La cosa era asi: yo tenia un dataset tipado, y le cambiaba el tipo de dato de Bool a Int, y el codigo se quejaba de que habia un problema de datos. Todo parecia bien, excepto que el choto del Visual Studio no me regeneraba el code behind del archivo .xsd para convertirlo a una clase, y seguia tomando como que el campo era Bool en vez de ser un Int.

Despues de renegar un rato (la mayoria de las veces es verdad, y uno intenta mandarle un valor que no corresponde al Dataset, y salta por error de tipos, pero en este caso, veiamos que en el Dataset Watcher el valor era FALSE en vez de ser 0 o 1), nos dimos cuenta la diferencia de ese dataset contra otros que existian en el proyecto: en este faltaba el valor en Custom Tool: todos los otros tenian MSDataSetGenerator, mientras el que no funcionaba estaba vacio.

Al agregarlo, se quedo pensando un rato y despues genero correctamente el CodeBehind de ese Dataset con los valores correspondientes.

Tambien paso que ese Dataset tenia vacio el Nombre (Name), asi que despues otras clases en la business dieron algunos errores. No se que fue lo que genero estos problemas, pero ya saben por donde buscar si alguna vez les pasa.