Angel Hernández

Lenguaje Ensamblador en .NET y algunas otras ideas

Hola Comunidad,

El siguiente post es sobre algo no tan nuevo en .NET que leí hace un tiempo atrás, pero para ese entonces no tenía blog Stick out tongue y como actualmente estoy leyendo de nuevo este libro "El arte del lenguaje ensamblador" (creo que por tercera vez, porque contiene demasiada información) pensé que sería interesante mencionarlo. Aunque .NET es código gestionado al final de cuentas lo que entiende el procesador es lenguaje de máquina que puede representarse simbólicamente a traves del lenguaje Ensamblador, lo mismo pasa con los demás lenguajes (gestionados y no gestionados). En el año 2001 ha alguien se le ocurrió la idea de hacer ASP.NET usando lenguaje ensamblador.  El artículo completo lo pueden ver acá y abajo pueden ver un ejemplo de como luce el código de la página

Lo poco que aprendí sobre lenguaje Ensamblador fue por allá en el año 1995, gracias a mi amiga Virginia que ya estaba por graduarse de Ingeniero de Sistemas y yo estaba recién entrando en universidad. Me la pasaba horas haciendo cosas con Microsoft C/C++ 7.0 (que traía consigo MFC 1.0) por lo que me parecía chévere poner código inline dentro del __asm al mismo tiempo estaba aprendiendo VB 4.0 y en los ratos libres jugando Heretic y MK II... Mientras mi mamá me peleaba para que fuera a comer Stick out tongue que buenos tiempos aquellos... de verdad que si... Una cosa que he tratado mantener con los años es eso de "hacer las cosas con pasión y aprender jugando" por eso creo que no me aburro de la computadora.

Cambiando de tema, en días pasados un cliente hizo un requerimiento, "quiero detectar cuando la sesión haya expirado y guardar el carrito de compras en CRM", claro... en ASP.NET puedo escribir algo en el Global.asax e interceptar el evento Session_End y es sencillo, pero esto es una solución basada en SharePoint que hace uso de autenticación basada en formas y como es bien sabido SharePoint viene a soportar este tipo de autenticación  a partir de la versión 2007, porque siempre ha utilizado NTLM y Kerberos para ello. En fin, se me ocurrieron un par de ideas las cuales menciono a continuación:

  • Toda aplicación basada en SharePoint es una instancia de SPHttpApplication que a la vez deriva de HttpApplication, al estar consciente de esto me dije "Nah... sencillo" con modificar el Global.asax y escribir código para el evento Session_End lo consigo... No funciona Sad entonces pensé en crear un proyecto y explicitamente derivar de SPHttpApplication  y tampoco funciona... Por lo que pensé en otra alternativa...

  • Crear un HttpModule que contiene un singleton y este a su vez mantiene una estructura que mediante una región crítica permite su actualización al “expirar alguna sesión”, el código es mostrado a continuación
  • using System;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.ApplicationRuntime;
    using System.IO;
    using Microsoft.SharePoint.Security;
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.Web.SessionState;
     
     
    namespace Demo {
        public class MyCustomApplication : IHttpModule {
            #region IHttpModule Members
            private SyncedInfo _synced = null;
            private GCHandle? _allocatedMem = null;
     
            private GCHandle? AllocatedMemory {
                get {
                    return _allocatedMem;
                }
                set {
                    _allocatedMem = value;
                }
            }
     
            private SyncedInfo Singleton {
                get {
                    return _synced;
                }
                set {
                    _synced = value;
                }
            }
     
            public void Dispose() {
                if (AllocatedMemory != null) {
                    AllocatedMemory.Value.Free();
                }
            }
     
            public void Init(HttpApplication context) {
                if (Singleton == null) {
                    Singleton = new SyncedInfo(context.Modules["Session"]);
                    AllocatedMemory = GCHandle.Alloc(Singleton);
                }
            }
            #endregion
        }
     
        [Serializable]
        public class SyncedInfo {
            protected SessionStateModule _sessionModule;
            protected HttpContext _currentContext = HttpContext.Current;
     
            public SyncedInfo(IHttpModule context) {
                _sessionModule = (SessionStateModule)context;
                _currentContext.Application["UserData"] = new Dictionary<string, string>();
                _sessionModule.Start += Session_Start;
                _sessionModule.End += Session_End;
            }
     
            public bool Push(string customer, string selectedData) {
                bool retval = false;
                object userData = _currentContext.Application["UserData"];
     
                try {
                    lock (userData) {
                        if (!((Dictionary<string, string>)userData).ContainsKey(customer)) {
                            ((Dictionary<string, string>)userData).Add(customer, selectedData);
                        } else {
                            ((Dictionary<string, string>)userData)[customer] = selectedData;
                        }
                        retval = true;
                    }
                } catch { } // Swallow the exception
                return retval;
            }
     
            public KeyValuePair<string, string>? Pop(string customer) {
                KeyValuePair<string, string>? retval = null;
                object userData = _currentContext.Application["UserData"];
     
                try {
                    lock (userData) {
                        if (((Dictionary<string, string>)userData).ContainsKey(customer)) {
                            retval = new KeyValuePair<string, string>(customer, ((Dictionary<string, string>)userData)[customer]);
                            ((Dictionary<string, string>)userData).Remove(customer);
                        }
                    }
                } catch { retval = null; } // Swallow the exception
                return retval;
            }
     
            private void Session_End(object sender, EventArgs e) {
                // Serialize data here (Pop)
     
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate() {
                    WriteActivity(false);
                }));
     
            }
     
            private void Session_Start(object sender, EventArgs e) {
                // Push should be call from the App (UI)
     
                SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate() {
                    WriteActivity(true);
                }));
            }
     
            private void WriteActivity(bool state) {
                string fileName = @"c:\log.txt";
     
                try {
                    using (StreamWriter logWriter = (!File.Exists(fileName) ? File.CreateText(fileName) : File.AppendText(fileName))) {
                        logWriter.WriteLine(string.Format("Session {0} at {1}", new object[] { (state ? "Started" : "Ended"), DateTime.Now }));
                        logWriter.Flush();
                        logWriter.Close();
                    }
                } catch { } // Swallow exception
            }
        }
    }

Esta solución debería funcionar, de hecho lo hace cuando Session_Start es disparado pero no cuando la sesión expira lo cual me molesta pues SharePoint me está quitando algo ofrece ASP.NET,  quizás esto no aplica cuando la seguridad está basada en Windows pero puede darse el caso con autenticación basada en formas sí.

Entonces es posible hacer ASP.NET con lenguaje Ensamblador (según el artículo antes mencionado) pero no puedo interceptar el cierre de una sesión en SharePoint Sad  Que les parece!!!!

Saludos,

Angel

Leave a Comment

(required) 

(required) 

(optional)

(required)