viernes, 24 de mayo de 2013

Profile in Web Application Solution

Hi everybody,

Here I am again with something that I am pretty sure that will help some people to solve the problem to use the asp .NET persistent profile functionality with new Web Application projects or migrated Websites projects into that solution type.

I expended a lot of time trying to retrieve the data from the aspnet_profile table but the Profile.GetProfile() function does not exist neither the HttpContext.Current.Profile bring me any data.

looking for a solution, I found that I need to create a custom class, ProfileBase inherited with the methods GetProfile to create the profile calling the create method of the ProfileBase SuperClass and return the data converting it to the created class with cast, but always return Nothing because error casting.

So, what I did.

Web.Config

<profile defaultProvider="SqlProvider"  enabled="true">
      <providers>
        <clear />
        <add name="SqlProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="EDI" applicationName="ediprov" description="SQLProfile provider for EDI" />
      </providers>
      <properties>
        <add name="Nombre" type ="string"/>
        <add name="SAPKey" type ="string"/>
      </properties>
    </profile>

Saving the profile

To save the profile I only used the ProfileBase like this

Dim profile As ProfileBase = ProfileBase.Create(CreateUserWizard1.UserName, True)
        profile("Nombre") = TxtNombre.Text
        profile("SAPKey") = txtSAPKey.Text
        profile.Save()

Retrieving the Profile Data from Database

I make a class to retrieve the data from the database and fill the HttpContext.Current.Profile properties for a user, so then we can use it.

Imports System.Web.Profile
Imports System.Data
Imports System.Data.SqlClient
Public Class UserProfile
    Inherits ProfileBase
    Public Shared Sub GetUserProfile(UserName As String)
        Dim con As SqlConnection = Nothing
        Try
            Dim rootWebConfig As System.Configuration.Configuration
            rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/" & ConfigurationManager.AppSettings("SiteName"))
            con = New SqlConnection(rootWebConfig.ConnectionStrings.ConnectionStrings("EDI").ToString())
            Dim Cmd As SqlCommand
            Dim dt As New DataTable
            Dim da As New SqlDataAdapter
            '
            Cmd = Con.CreateCommand
            Cmd.Connection.Open()
            Cmd.CommandText = "SELECT * FROM aspnet_profile where userid in (SELECT userid FROM aspnet_users WHERE UserName = '" & UserName & "')"
            da.SelectCommand = Cmd
            da.Fill(dt)
            Dim cntproperties As Long
            Dim arrPSettings() As String
            For Each dr As DataRow In dt.Rows
                arrPSettings = dr("PropertyNames").ToString.Split(":")
                cntproperties = arrPSettings.Count / 4
                For ix = 0 To cntproperties Step 4
                    HttpContext.Current.Profile.SetPropertyValue(arrPSettings(ix), dr("PropertyValuesString").ToString.Substring(arrPSettings(ix + 2), arrPSettings(ix + 3)))
                Next
            Next
        Catch ex As Exception
        Finally
            con.Close()
        End Try
    End Sub
    Public Property Nombre() As String
        Get
            Return HttpContext.Current.Profile.GetPropertyValue("Nombre")
        End Get
        Set(value As String)
            value = HttpContext.Current.Profile.GetPropertyValue("Nombre")
        End Set
    End Property
    Public Property SAPKey() As String
        Get
            Return HttpContext.Current.Profile.GetPropertyValue("SAPKey")
        End Get
        Set(value As String)
            value = HttpContext.Current.Profile.GetPropertyValue("SAPKey")
        End Set
    End Property
End Class

Retrieving the Profile

If you use MasterPages it is effort saving to call the GetUserProfile there to have the Context Updated,
calling it like this.

UserProfile.GetUserProfile(HttpContext.Current.User.Identity.Name)

After this you can get the property values from,

HttpContext.Current.Profile.GetPropertyValue("Nombre")

Hope it helps,

Greetings

lunes, 29 de agosto de 2011

Desbloquear usuario Membership

Membership bloquea un usuairo si tiene 5 intentos fallidos o despues de cierto tiempo, de forma predeterminada, para desbloquearlo es necesario ejectuar el Metodo UnlockUser del usuario de la siguiente manera.

MembershipUser usuario = Membership.GetUser(nombreusuario);
usuario.UnlockUser();


jueves, 19 de mayo de 2011

Tail

Buscando en la red encontré una base en Code Project para una aplicación de escritorio, teniendo el siguiente código en C#:

using ( StreamReader reader = new StreamReader(new FileStream(fileName, 
                     FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) )
{
    //start at the end of the file
    long lastMaxOffset = reader.BaseStream.Length;

    while ( true )
    {
        System.Threading.Thread.Sleep(100);

        //if the file size has not changed, idle
        if ( reader.BaseStream.Length == lastMaxOffset )
            continue;

        //seek to the last max offset
        reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin);

        //read out of the file until the EOF
        string line = "";
        while ( (line = reader.ReadLine()) != null )
            Console.WriteLine(line);

        //update the last max offset
        lastMaxOffset = reader.BaseStream.Position;
    }
}

 intentando aplicarlo en ASP.NET  surgen 3 detalles.
  1. No es posible utilizar un loop infinito (While true) ya que la manera de escribir en la página Web es utilizando Response.Write o ejecutando una función javascript del lado del cliente desde el lado del servidor donde dicha función realice un document.write, Response requiere un Request el cual se recibe en el Load y la función javascript requiere un postback para que se actualice la info insertada, se tiene la restricción de cargar el log en el evento Load y si se utiliza el loop infinito en el Load la pagina nunca cargaria.
  2. Se requiere un timer para que este cargando los cambios realizados del archivo y para que los cambios sean mostrados es necesario un Request o Postback.
  3. Una vez logrado lo anterior es necesario que el scroll este siempre al final donde las últimas modificaciones se encuentran.
Teniendo en cuenta lo anterior comenzaremos a buscar soluciones para realizar la tarea :).

Resultado:

Al final para lograr el monitoreo de los log lo que realicé fue lo siguiente:

1.- Creé una función javascript que inicializa un timer dejándolo a 30 segundos.
    function StartTimer() {
         setTimeout('DoPostBack()', 30000);
    }
2.- Agregué un botón con un clientID=Button1 para forzar un PostBack, con el click de dicho botón desde javascript.
3.- La función encargada de forzar el click, forza el PostBack y hay un request para poder utilizar el response, después vuelve a asignar el timer a la misma función haciéndola recursiva.
    function DoPostBack() {
        var btn = document.getElementById('Button1');
        if (btn != null)
        {
            btn.click();
            StartTimer();
        }
        else
        {
            alert('No encontre el botón.');
        }
    }
4.- Se creo una función javascript donde se logró el scrollTop, llamandola desde el OnLoad del body en nuestro html, con una llamada a la función timer para iniciar la recursión.
    function scrollme() {
        dh = document.body.scrollHeight
        ch = document.body.clientHeight
        if (dh > ch) {
            moveme = dh - ch
            window.scrollTo(0, moveme)
        }
        StartTimer();
    }
5.- En el metodo Page_Load quedo de la siguiente manera:
If Not Page.IsPostBack Then
            'Inicio de Página
            If Not Request.QueryString("FPath") Is Nothing And Request.QueryString("Offset") Is Nothing Then
                Try
                    FPath = Request.QueryString("FPath").ToString.Trim
                    Dim reader As New StreamReader(New FileStream(FPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    Dim line As String
                    lastMaxOffset = reader.BaseStream.Length
                    ' Read and display the lines from the file until the end
                    ' of the file is reached.
                    Do
                        line = reader.ReadLine()
                        Response.Write("<font color='" & AppSettings("ForeColor") & "'>" & line & "</font><br/>")
                    Loop Until line Is Nothing
                    'Actualizar Url con Offset Actual para uso posterior con PostBack
                    Response.Redirect(Request.Url.AbsolutePath & "?FPath=" & FPath & "&Offset=" & lastMaxOffset)
                Catch ex As Exception
                    Response.Write("<font color='red'>" & ex.ToString & "</font><br/>")
                End Try
            Else
                'Cargar info de Offset en adelante
                Try
                    FPath = Request.QueryString("FPath").ToString.Trim
                    Dim reader As New StreamReader(New FileStream(FPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    Dim line As String
                    lastMaxOffset = Request.QueryString("Offset").ToString.Trim
                    ' Read and display the lines from the file until the end
                    ' of the file is reached.
                    Do
                        line = reader.ReadLine()
                        Response.Write("<font color='" & AppSettings("ForeColor") & "'>" & line & "</font><br/>")
                    Loop Until line Is Nothing
                Catch ex As Exception
                    Response.Write("<font color='red'>" & ex.ToString & "</font><br/>")
                End Try
            End If
        ElseIf Not Request.QueryString("FPath") Is Nothing And Not Request.QueryString("Offset") Is Nothing Then
            Dim FilePathParam As String = Request.QueryString("FPath").ToString.Trim
            Dim OffsetParam As Long = FPath = Request.QueryString("Offset").ToString.Trim
            Dim reader As New StreamReader(New FileStream(FilePathParam, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            If reader.BaseStream.Length > OffsetParam Then
                'seek to the last max offset
                reader.BaseStream.Seek(OffsetParam, SeekOrigin.Begin)
                'read out of the file until the EOF
                While reader.BaseStream.Length > reader.BaseStream.Position
                    Response.Write("<font color='" & AppSettings("ForeColor") & "'>" & reader.ReadLine & "</font><br/>")
                End While
                'update the last max offset
                OffsetParam = reader.BaseStream.Position
            End If
        End If
    End Sub

Podemos observar que:
   ° Al iniciar la página trae solo el parámetro FPath que contiene la ruta del log entrando en la primer condicionante If donde se carga el contenido actual del archivo y hace una redirección con Response.Redirect hacia la misma página,agregando el parámetro Offset con la posición donde se quedo.
    ° Despues de la redirección no siendo aun un PostBack entra en el else donde carga el contenido nuevo en caso de existir partiendo del Offset.
    ° A los 30 seg. asignados se dispara el click del botón siendo este un Postback accediendo a la parte del codigo en el ElseIf del primer If donde carga los cambios existentes partiendo del Offset.

Con esto obtuve una aplicación Web tipo Unix Tail

También hice posible que el color tanto de fondo como de la fuente quedaran configurables desde el Web.Config como se observa en el Response.Write utilizando Appsettings

Espero sea de utilidad.