Datos personales

miércoles, 18 de abril de 2012

IPN Paypal – Retorno de Variables a Asp.net – Vb

Después de tanto tiempo he logrado recuperar las variables que retornan a mi Website después de un Pago hecho con Paypal. Voy a explicar cómo logramos nuestro objetivo:
Ipn Paypal: La Notificación de Pago Instantanea, es una   funcionalidad muy útil con la cual podemos interactuar con nuestra propia aplicación. Básicamente, nos da la posibilidad de tomar decisiones en el caso que el pago haya sido confirmado o bien ejecutar determinadas rutinas en nuestro programa si el pago no fue aceptado.
Para caso de ejemplo vamos a mutilizar una herramienta de prueba que nos da Paypal, llamada Sandbox, donde podemos crear cuentas de prueba y simular un caso de compra venta con dichas cuentas, claro está, con dinero ficticio
Pasos para configurar IPN
1.       Ingresamos al siguiente link https://developer.paypal.com/us/cgi-bin/ . Si no tenemos una cuenta Sandbox, creamos una. Al finalizar la creación de la cuenta nos llegará un email a nuestra cuenta de correo para dándonos la bienvenida a Sandbox. En mi caso, ya tengo una cuenta creada, así que procedo a Loguearme.
Nota: Tratar de evitar que la cuentas de correo y password sean las mismas de nuestra cuenta paypal, ya que si entregas estas credenciales a otra persona, tendrá acceso a tu cuenta Paypal


2.       Ya dentro de Sandbox vemos un Panel de opciones al lado izquierdo de la página. Ingresamos a la Opción Test Accounts. Aquí es donde crearemos nuestras cuentas de Prueba. Hacemos clic en “New Test Account: Preconfigured”
Nota: Es importante tomar nota del password autogenerado, para poder ingresar posteriormente a las cuentas de prueba
Primero creamos una cuenta Personal (cliente). Para ello elegimos la opción Buyer Aquí ingresamos los datos necesarios. El email lo dejamos igual, ya que Sandbox, generará una cuenta email aleatoria no real. En mi caso, como hará pruebas, en el campo Account Balance coloqué 5000 dólares de saldo. Hacemos clic en Create Account


3.       Ahora seguimos el PASO 2, y nuevamente creamos una cuenta, pero esta vez Cuenta Business (Opción Seller). Clic en Create Account

4.       Ahora nuestro Panel principal debería quedar de la siguiente forma:
En círculos estoy identificando los tipos de cuentas.



5.       Para mi ejemplo he creado una aplicación en Asp.net 2005 – Vb, con la que envio datos a Paypal, y luego recepciono las variables. Para ellos vamos a crear dos páginas:
La primera página tendrá la siguiente forma:

Y su codeBehind es el siguiente:
Partial Class paypal_sendPaypal
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim item As String = "Lapiz"
        Dim link As String = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_xclick&business=raydia_1334695546_biz@misitio.com&item_name=" + item + "&amount=" + CStr(50.5) + "&no_shipping=1&item_number=Feb2012004563" '         Response.Redirect(link)
    End Sub
End Class

Con este código, le indico a Paypal (Sandbox): la cuenta business (quien vende), el ítem (articulo), el amount(precio) y ítem_number (código del articulo)




La 2da página (para mi ejemplo) es una Página en blanco que al recibir los datos de PayPal (Sandbox), enviará un email a mi cuenta de correo (el manejo de la información recibida, depende de cada necesidad) con todos los datos recibidos
Muestro el codeBehind: ipn.aspx.vb
Nota: Esta clase la da Paypal, solo hay que adaptarla a lo que necesitamos https://cms.paypal.com/mx/cgi-bin/?cmd=_render-content&content_ID=developer/library_code_ipn_code_samples

Imports System.Net
Imports System.IO
Imports Capa_negocio
Partial Class paypal_ipn
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        'Aqui definimos de quein vamos a recibir valores de Paypal o Sandbox. Para este ejemplo usaremos la variable strSandbox
        Dim strSandbox As String = "https://www.sandbox.paypal.com/cgi-bin/webscr"
        Dim strLive As String = "https://www.paypal.com/cgi-bin/webscr"

        Dim req As HttpWebRequest = CType(WebRequest.Create(strSandbox), HttpWebRequest) ' creamos el request

        'Set values for the request back
        req.Method = "POST"
        req.ContentType = "application/x-www-form-urlencoded"
        Dim Param() As Byte = Request.BinaryRead(HttpContext.Current.Request.ContentLength)
        Dim strRequest As String = Encoding.ASCII.GetString(Param)

        strRequest = strRequest + "&cmd=_notify-validate" ' hasta aqui ya tenemos recuprados los valores
        Dim x As String = strRequest
        req.ContentLength = strRequest.Length

        'for proxy
        'Dim proxy As New WebProxy(New System.Uri("http://url:port#"))
        'req.Proxy = proxy

        'Send the request to PayPal and get the response
        Dim streamOut As StreamWriter = New StreamWriter(req.GetRequestStream(), Encoding.ASCII)
        streamOut.Write(strRequest)
        streamOut.Close()
        Dim streamIn As StreamReader = New StreamReader(req.GetResponse().GetResponseStream())
        Dim strResponse As String = streamIn.ReadToEnd()

        Dim objEmail As New clsEmail 'clase personalizada para envio de correos (propia)
        Dim SUBJECT As String


        If strResponse = "VERIFIED" Then ' si el proceso terminó correctamente
            SUBJECT = "Confirmación Paypal - BIEN - " & Date.Now
            Dim mensaje As String = ""
            Try
                'el strRequest, viene en un formato var=valor&var1=valor1....Por tanto lo descompongo con 2 SPLIT
                'El primero para separar por el caracter "&" : var=valor 
                'El segundo para separar por el caracter "=" :
                'Como las variables vienen de una url, vienen con una codificacion que no es totalmente legible
                '(ejemplo @ se representa por %40, ect) utilizamos HttpUtility.UrlDecode para decodificar los datos extraidos

                Dim descomponer() As String = strRequest.Split("&")
                For i As Integer = 0 To descomponer.Length - 1
                    Dim linea As String = descomponer(i)
                    Dim dividir() As String = linea.Split("=")
                    mensaje = mensaje & dividir(0) & vbTab & ":" & vbTab & HttpUtility.UrlDecode(dividir(1)) & vbCrLf
                Next
                objEmail.SendMail(objEmail.emailFrom, objEmail.mailPruebas, "", SUBJECT, "Paypal está OK - " & vbCrLf & mensaje, _
                    False, System.Net.Mail.MailPriority.High)
            Catch ex As Exception
                Throw
            End Try

        ElseIf strResponse = "INVALID" Then
            SUBJECT = "Confirmación Paypal - MAL - " & Date.Now
            Try
                objEmail.SendMail(objEmail.emailFrom, objEmail.mailPruebas, "", SUBJECT, "Paypal está INVALIDO", _
                    True, System.Net.Mail.MailPriority.High)
            Catch ex As Exception
                Throw
            End Try

            'log for manual investigation
        Else
            SUBJECT = "Confirmación Paypal - NO SE - " & Date.Now
            Try
                objEmail.SendMail(objEmail.emailFrom, objEmail.mailPruebas, "", SUBJECT, "Paypal está - NINGUNA", _
                    True, System.Net.Mail.MailPriority.High)
            Catch ex As Exception
                Throw
            End Try
            'Response wasn't VERIFIED or INVALID, log for manual investigation
        End If
        streamIn.Close()
    End Sub

End Class

6.       Ahora que ya tenemos nuestras páginas, vamos a configurar la Url de Retorno nuestra cuenta Business para que al finalizar un Pago PayPal, las variables retornen a nuestra página ipn.aspx. Para ello seleccionamos la cuenta Business y hacemos clic en ENTER SANSBOX TEST SITE


7.       Dentro de nuestra cuenta Business, hacemos clic en Perfil

8.       En Perfil, hacemos clic en la opción Preferencias de Notificación de Pago Instantanea

9.       Hacemos clic en Editar Configuración, y escribimos la dirección url de nuestra página IPN.aspx. También hacemos clic en Recibir mensajes IPN. Clic en Guardar


10.       Ok, hasta aquí ya tenemos configurada nuestra cuenta para que envie mensajes a nuestra página Ipn.aspx. Ahora probamos nuestra Aplicación





11.       Al revisar mi cuenta de correo Eléctrónico, llegó esto:

Espero haber sido de ayuda. Saludos

viernes, 23 de diciembre de 2011

Problema ScriptResource.axd - Acceso Denegado de javascript en sitios con frames

Estoy desarrollando una aplicacion que muestra en un iframe otra aplicacion que contiene controles calendar ajax. El problema es que no despliega el calendario y aparece el siguiente error :

Mensaje: Acceso denegado.
Línea: 5959
Carácter: 49
Código: 0
URI: http://192.200.4.248/NOMBRE_APLICACION/ScriptResource.axd?d=2TUSrXlGiZ-YhriQIxHvs2j2r3CD-1dxiNch9HtINJ1-xYqYmXVZ2MxqzBF9v_CRUg-thDlUW3uXGz_vysgmtwWzobIsUaqbRwJQzvcSjKo1&t=633093755470531249 

Ese o en lugar de ScriptResource.axd. El punto es que la solución está en usar unos archivos de scripts modificados directamente en nuestros ScriptManagers. Esto se hace de la siguiente manera (en cada página que tenga un ScriptManager):

    <asp:ScriptManager ID="ScriptManager1" runat="server" >
        <Scripts>
            <asp:ScriptReference Name="MicrosoftAjax.js" ScriptMode="Auto" Path="../Includes/MicrosoftAjax.js"/>
        </Scripts>
    </asp:ScriptManager>

Adjunto aquí el par de archivos requeridos (MicrosoftAjax.js y MicrosoftAjax.debug.js).


Referencia:
http://creeperionet.blogspot.com/2011/12/problema-acceso-denegado-de-javascript.html

miércoles, 7 de diciembre de 2011

ERROR ASP NET : The source file is different from when the module was built

A esto se le suele llamar Dessincronización de Código
"There is no source code available for the current location" Error que emite Visual Studio en medio del debuggueo. Se da porque se produce una desincronización entre los diferentes proyectos de una solución (entre otras razones). Si al aparecernos por primera vez le dimos en el boton "NO" Entonces Visual Studio guardará una referencia del proyecto problemático para ignorarlo las proximas veces que se debuggea, por lo que cada vez que queremos depurar ese código nos va a aparecer "There is no source code available for the current location" para deseperarnos. 

Para solventar esta situación damos clic derecho sobre la Solución (NO sobre el proyecto). En "Common Properties" vamos a "Debug Source Files" y una vez ahi borramos las entradas del proyecto problematico que se encuentren en la sección inferior de la pantalla de la derecha denominada "Do not look for these source files". Esto provocará que Visual Studio no ignore las entradas del proyecto y nos permita de debugguearlo. 

Finalmente mientras nos encontramos en las properties de la Solucion, Nos vamos "Configuration Properties" y dentro de esta a "Configuration" y nos aseguramos que el check "Build" de los proyectos este checkeado, lo cual le indicará a Visual Studio que estos proyectos tienen que compilarse cuando ejecutamos la solucion en modo de debuggeo. Damos clic en aceptar y Generamos. Ya con esto deberíamos tener sincronizado nuestro código y el error en cuestión debería dejar de rondar por nuestra solución.

Lo último es ir a las carpetas donde se generan las dll de los proyectos (en mi caso bussiness y data) y eliminar las carpetas bin y obj. Volver a generar el proyecto y listo.

martes, 6 de diciembre de 2011

Errores ASP.NET en web farms muy comunes - Validation of viewstate MAC failed

Errores ASP.NET en web farms muy comunes

Hay veces que tenemos una aplicacion web ASP.NET que está alojada en un Proveedor de Internet o ISP y se instala en una granja de servidores web o "WebFarm" que no es ni más ni menos que varios servidores en paralelo que actúan como si fuera uno solo por si se cae uno y responda a las peticiones web otro servidor de la granja de forma transparente al usuario. En esos casos a veces despues de entrar en un area privada de nuestra aplicacion web que usa variables de sesion inexplicablemente nos sale un error parecido a esto y nos dice que debemos tocar el Machine.config pero el servidor no es nuestro!:
Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.
Esto está muy bien para conseguir Redundancia y alta disponibilidad mediante los servicios de Clustering de Windows 2003 pero tiene una pega para nuestros compañeros los desarrolladores web. ¿Cual? Pues que cuando usamos variables de sesión en nuestra aplicación web , estas quedan almacenadas por defecto en el servidor web que estaba ejecutando la aplicación y si este cae por un fallo hardware o de comunicación por ejemplo entonces otro servidor web que no tiene tus variables de sesion recogerá las peticiones http a tu web y no sabrá quien eres si identificabas a tu visitante con un Session("idusuario") recogido por ejemplo al autentificarse en la web.
Para esto veo 2 soluciones posibles :
1- Poner esto en el web.config <pages enableViewStateMac="false" /> como sugieren algunos ISP. Ojo, esto debe ponerse dentro de <system.web></system.web>
Esta propiedad tambien puede aplicarse a paginas web aspx individuales en la directiva <@Page %>  y por defecto suele ser false. Aqui teneis mas informacion sobre la propiedad en la MSDN. Para el que no lo sepa , esta directiva se usa para evitar la corrupxion o alteración de los datos conforme se envían a una pagina web.
2- Habilitar el estado de las sesiones en SQL Server. Al estar las sesiones en el servidor de base de datos, es independiente de que se caiga el servidor web, pues podrá recuperar las sesiones de una base de datos externa al servidor web. En este articulo podeis ver como configurar sql server para ello, pero tened en cuenta que debéis ser administradores del servidor y no servirá en un alojamiento compartido a no ser que seais "amigo" del propietario del servidor :-)
NOTA: Por defecto en el web config que se genera en Visual Studio el estado de sesion se guarda asi:
<sessionState
mode="InProc"
stateCon蠌ectionString="tcpip=127.0.0.1:42424"
sqlConnectio蚼String="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="20"
/>

AVISO IMPORTANTE:
No olvideis nunca cuando paséis a produccion vuesrtas web asp.net generar los ensamblados en modo Release y no Debug y cambiar estas lineas en el web.config para que queden así
<compilation defaultLanguage="vb" debug="false" /> 
¿Acaso vais a depurar la aplicacion en el servidor web de desarrollo? Con esto no teneis que subir a bin el fichero .pdb que se genera en asp.nett 1.x sino solo los ensamblados .dll
<customErrors mode="RemoteOnly" /> Para que los errores asp.net no aparezcan a usuarios que no estén en el servidor local y no puedan recopilar información para un ataque ;-)
Saludos

lunes, 19 de septiembre de 2011

Sumar valores de textbox ItemTemplate en FooterTemplate de DataGrid

Estoy trabajando una funcionalidad de sistema Asp.net 2.0. Hago uso de un datagrid, y tengo una columna de tipo textbox que solo debe aceptar valores numéricos. En el footer del datagrid, se deben sumas los valores de dichos textbox, tarea que se me hizo algo complicada, pero que ya logré realizarla.

Esta imagen muestra parte del datagrid que estoy usando (la suma no es correcta ya que solo tome las ultimas filas para la imagen)

El Itemtemplate del datagrid tiene la siguiente forma:



El código para hacer la suma es el siguiente:

Sub
sumarFooter()
Dim tabla As Table = CType(Me.dgreservas.Controls(0), Table) //el datagrid es una tabla, asi que lo convertimos a TABLA
Dim foot As DataGridItem = tabla.Controls(tabla.Controls.Count - 1) //el footer vendria a ser el total de controles de la tabla -1
Dim lblfoot As Label = foot.FindControl("lblFootComi")   //de esa ultima fila, obtengo el control donde se hará la sumaDim totalComision As Double = 0
For Each item As DataGridItem In dgreservas.Items  //recorro el datagrid y hago la suma
Dim txtComis As TextBox = CType(item.FindControl("txtcomision"), TextBox)
   If IsNumeric(txtComis.Text.Trim) Then
     totalComision = totalComision + Convert.ToDecimal(txtComis.Text)    End If
Next
lblfoot.Text = Str(totalComision)  //coloco la suma en el control que esta en el footer
End Sub


Espero haber ayudado un poquito. Saludos!!!