|
|
PayPal Standard Problem...
-
11-22-2006, 8:23 AM |
-
Bonsai Bruce
-
-
-
Joined on 10-26-2006
-
-
Posts 29
-
-
|
PayPal Standard Problem...
I've tried to get this resolved at the CSK forums, but the advice I've received just doesn't seem to be fixing my problem. The problem is that I get all the way through paying for the products at PayPal (sandbox) and when I click on "Return To Merchant" I am properly sent to thePayPal/PDTHandler.aspx page with the following error: No TransactionID - InvalidSystem.Exception: No TransactionID - Invalid
at TestCondition.AssertFailed(String message) in d:\ultimaweb\bruce@ztechsystems.net\eranaturalbeauty.com\wwwroot\App_Code\Utility\TestCondition.cs:line 153
at TestCondition.IsNotNull(Object o, String failMessage) in d:\ultimaweb\bruce@ztechsystems.net\eranaturalbeauty.com\wwwroot\App_Code\Utility\TestCondition.cs:line 21
at PDTHandler.Page_Load(Object sender, EventArgs e) in d:\ultimaweb\bruce@ztechsystems.net\eranaturalbeauty.com\wwwroot\PayPal\PDTHandler.aspx.cs:line 26
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
I'm using PayPal Standard. There is a valid, Verified Business Account in place. I tried to use the Admin > Payment Configuration page that I have online, but apparently I don't have the authority to make changes there... so I ran a debug locally, made the changes, and uploaded the newly revised web.config. In the PayPal account, IPN, PDT and Auto Return are all "On." The correct PDT ID is in my web.config. This should be a plain and simple scenario and I'm feeling very stupid for not getting it properly setup... and would appreciate any insight!
~ Bruce
|
|
-
11-22-2006, 8:04 PM |
-
itechcs
-
-
-
Joined on 10-21-2006
-
Indiana
-
Posts 298
-
-
|
Re: PayPal Standard Problem...
Can you post your code for the files "TestCondition.cs" and "PDTHandler.aspx.cs"?
William Eaton, MCSE iTech Computer Solutions, LLC www.itechcs.com
|
|
-
11-22-2006, 10:44 PM |
-
Bonsai Bruce
-
-
-
Joined on 10-26-2006
-
-
Posts 29
-
-
|
Re: PayPal Standard Problem...
Yes, I can, Mr. Eaton! TestCondition.cs using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; public static class TestCondition { public static void IsTrue(bool condition, string failMessage) { if (!condition) { AssertFailed(failMessage); } } public static void IsNotNull(object o, string failMessage) { if (o == null) { AssertFailed(failMessage); } } public static void IsNotEmptyString(string s, string failMessage) { if (s == string.Empty) { AssertFailed(failMessage); } } public static void IsNotNullOrEmptyString(string s, string failMessage) { if (!String.IsNullOrEmpty(s)) { AssertFailed(failMessage); } } public static void IsGreaterThanZero(int i, string failMessage) { if (i <= 0) { AssertFailed(failMessage); } } public static void IsGreaterThanZero(decimal i, string failMessage) { if (i <= 0) { AssertFailed(failMessage); } } // Function to test for Positive Integers. public static void IsNaturalNumber(String strNumber, string failMessage) { Regex regNotNaturalPattern = new Regex("[^0-9]"); Regex regNaturalPattern = new Regex("0*[1-9][0-9]*"); if (!regNotNaturalPattern.IsMatch(strNumber) && regNaturalPattern.IsMatch(strNumber)) { AssertFailed(failMessage); } } // Function to test for Positive Integers with zero inclusive public static void IsWholeNumber(string strNumber, string failMessage) { Regex regNotWholePattern = new Regex("[^0-9]"); if (regNotWholePattern.IsMatch(strNumber)) { AssertFailed(failMessage); } } // Function to Test for Integers both Positive & Negative public static void IsInteger(string strNumber, string failMessage) { Regex regNotIntPattern = new Regex("[^0-9-]"); Regex regIntPattern = new Regex("^-[0-9]+$|^[0-9]+$"); if (regNotIntPattern.IsMatch(strNumber) && regIntPattern.IsMatch(strNumber)) { AssertFailed(failMessage); } } // Function to test whether the string is valid number or not public static void IsNumber(string strNumber, string failMessage) { Regex regNotNumberPattern = new Regex("[^0-9.-]"); Regex regTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*"); Regex regTwoMinusPattern = new Regex("[0-9]*[-][0-9]*[-][0-9]*"); String strValidRealPattern = "^([-]|[.]|[-.]|[0-9])[0-9]*[.]*[0-9]+$"; String strValidIntegerPattern = "^([-]|[0-9])[0-9]*$"; Regex regNumberPattern = new Regex("(" + strValidRealPattern + ")|(" + strValidIntegerPattern + ")"); if (regNotNumberPattern.IsMatch(strNumber) && !regTwoDotPattern.IsMatch(strNumber) && !regTwoMinusPattern.IsMatch(strNumber) && regNumberPattern.IsMatch(strNumber)) { AssertFailed(failMessage); } } // Function To test for Alphabets. public static void IsAlpha(string strToCheck, string failMessage) { Regex regAlphaPattern = new Regex("[^a-zA-Z]"); if (regAlphaPattern.IsMatch(strToCheck)) { AssertFailed(failMessage); } } public static void IsValidEmail(string email, string failMessage) { string emailPattern = @"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$"; Regex regEmailPattern = new Regex(emailPattern); if (regEmailPattern.IsMatch(email)) { AssertFailed(failMessage); } } // Function to Check for AlphaNumeric. public static void IsAlphaNumeric(string strToCheck, string failMessage) { Regex regAlphaNumericPattern = new Regex("[^a-zA-Z0-9]"); if (regAlphaNumericPattern.IsMatch(strToCheck)) { AssertFailed(failMessage); } } static void AssertFailed(string message) { throw new Exception(message); } } PDTHandler.aspx.cs using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Net; using System.IO; using Commerce.Common; public partial class PDTHandler : System.Web.UI.Page { void Page_Load(object sender, EventArgs e) { //############################################################################### // Page Validators //############################################################################### //your transaction ID can be null/empty if your account is not validated, verified, if //your business email is wrong, your PDT id is wrong, or PayPal's just having a bad day TestCondition.IsNotNull(Request.QueryString["tx"], "No TransactionID - Invalid"); TestCondition.IsNotNull(Request.QueryString["cm"], "No TransactionID - Invalid"); //############################################################################## string ppTX = Request.QueryString["tx"].ToString(); string sOrderID = Request.QueryString["cm"].ToString(); string pdtResponse = GetPDT(ppTX); //all we need at this point is the SUCCESS flag if (pdtResponse.StartsWith("SUCCESS")) { string sAmount = GetPDTValue(pdtResponse, "mc_gross"); //make sure the totals add up try { //make sure to unencode it sOrderID = Server.UrlDecode(sOrderID); Order order = OrderController.GetOrder(sOrderID); if (order != null) { //commit the order OrderController.CommitStandardOrder(order, ppTX, decimal.Parse(sAmount)); //send off to the receipt page Response.Redirect("../receipt.aspx?t=" + sOrderID, true); } else { Response.Write("Can't find the order"); } } catch (Exception x) { Response.Write("Invalid Order: " + x.Message); } } else { Response.Write("PDT Failure: " + pdtResponse); } } string GetPDTValue(string pdt, string key) { string[] keys = pdt.Split('\n'); string thisVal = ""; string thisKey = ""; foreach (string s in keys) { string[] bits = s.Split('='); if (bits.Length > 1) { thisVal = bits[1]; thisKey = bits[0]; if (thisKey.ToLower().Equals(key)) break; } } return thisVal; } string GetPDT(string transactionID) { string sOut = ""; string PDTID = ""; PDTID = SiteConfig.PayPalPDTID; string sCmd = "_notify-synch"; string serverURL = ""; if (SiteConfig.UsePPStandardSandbox) { serverURL = "https://www.sandbox.paypal.com/cgi-bin/webscr"; } else { serverURL = "https://www.paypal.com/cgi-bin/webscr"; ; } try { string strFormValues = Request.Form.ToString(); string strNewValue; string strResponse; // Create the request back HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serverURL); // Set values for the request back req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; strNewValue = strFormValues + "&cmd=_notify-synch&at=" + PDTID + "&tx=" + transactionID; req.ContentLength = strNewValue.Length; // Write the request back IPN strings StreamWriter stOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII); stOut.Write(strNewValue); stOut.Close(); // Do the request to PayPal and get the response StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream()); strResponse = stIn.ReadToEnd(); stIn.Close(); sOut = Server.UrlDecode(strResponse); } catch (Exception x) { } return sOut; } }
Hope that helps you figure out why things aren't working! Thanks!
~ Bruce
|
|
-
11-24-2006, 7:55 AM |
-
Ultima Mark
-
-
-
Joined on 09-05-2006
-
-
Posts 480
-
-
|
Re: PayPal Standard Problem...
Hi Bruce, Are there any values in your URL when you are passed back from PP? Cheers, Mark
System Administrator
|
|
-
11-24-2006, 9:00 AM |
-
11-24-2006, 9:15 AM |
-
Ultima Mark
-
-
-
Joined on 09-05-2006
-
-
Posts 480
-
-
|
Re: PayPal Standard Problem...
Hi Bruce, No I mean the URL when you are being sent back but before it hits your site - this usually contains the return URL value and well as PTD etc. Cheers, Mark
System Administrator
|
|
-
11-24-2006, 9:54 AM |
-
pzycoman
-
-
-
Joined on 09-27-2006
-
London, UK
-
Posts 24
-
-
|
Re: PayPal Standard Problem...
I believe that's going to be the problem then - I did some paypal integration (2 years ago now, geez im getting old) - it needs 2 parameters in the querystring for it to work properly... If your still having trouble, i can try digging out some of my old code, and going thru my paypal sandbox account...
Senior C#.net Developer
|
|
-
11-24-2006, 12:22 PM |
-
itechcs
-
-
-
Joined on 10-21-2006
-
Indiana
-
Posts 298
-
-
|
Re: PayPal Standard Problem...
I think I see your problem. In your TestCondition.cs file, you have a function called "AssertFailed", where you re-throw an error message: public static void IsNotNull(object o, string failMessage) { if (o == null) { AssertFailed(failMessage); }
....... static void AssertFailed(string message) { throw new Exception(message); } However, in the calling page (PDTHandler), you don't handle that error (i.e. Try..Catch): //your transaction ID can be null/empty if your account is not validated, verified, if //your business email is wrong, your PDT id is wrong, or PayPal's just having a bad day TestCondition.IsNotNull(Request.QueryString["tx"], "No TransactionID - Invalid"); TestCondition.IsNotNull(Request.QueryString["cm"], "No TransactionID - Invalid"); Add a Try Catch around your TestCondition.IsNotNull calls and see if that works.
William Eaton, MCSE iTech Computer Solutions, LLC www.itechcs.com
|
|
-
11-24-2006, 1:20 PM |
-
pzycoman
-
-
-
Joined on 09-27-2006
-
London, UK
-
Posts 24
-
-
|
Re: PayPal Standard Problem...
You dont want to handle that error though, as without the 2 querystrings, the paypal transaction was incomplete / invalid, so you DO want it to fail...
Senior C#.net Developer
|
|
-
11-24-2006, 3:35 PM |
-
itechcs
-
-
-
Joined on 10-21-2006
-
Indiana
-
Posts 298
-
-
|
Re: PayPal Standard Problem...
Handling the error is just a way to indicate that something didn't happen as expected. That doesn't mean the error should be ignored. The missing querystring values (tx and cm) should be validated (as they are), but in this case it seems they are missing (empty/null), so the user should be given a more user friendly error message, instead of the System.Exception error. Here is some psudo-code: //your transaction ID can be null/empty if your account is not validated, verified, if //your business email is wrong, your PDT id is wrong, or PayPal's just having a bad day Try
TestCondition.IsNotNull(Request.QueryString["tx"], "No TransactionID - Invalid"); TestCondition.IsNotNull(Request.QueryString["cm"], "No TransactionID - Invalid");
Catch ex as exception //You could take this opportunity to email yourself the error details....do it here before you transfer the user to another page. This is some VB code I use that was translated to C#. Forgive me if the translation is not entirely accurate: string LastException = Context.Error.ToString(); Context.ClearError(); string strDetails; strDetails = "Date/Time: " + Now() + "<BR>"; strDetails = strDetails + "URL: " + Request.ServerVariables("HTTP_REFERER") + "<BR>"; strDetails = strDetails + "<BR>"; strDetails = strDetails + LastException; strDetails = strDetails + "<BR><BR>"; strDetails = strDetails + "<b>ServerVariable Collection:</b>"; strDetails = strDetails + "<BR>"; foreach string x in Request.ServerVariables) { strDetails = strDetails + x + " = " + Request.ServerVariables(x) + "<BR><BR>"; } //Use or Create your own SendMail procedure SendMail("from email", "to email", "Subject", strDetails);
//Now redirect to a generic error page showing them a user-friendly error message. string ErrMsg = "We're sorry, there was an error processing your transaction. Please contact us."; server.Transfer("error.aspx?err=" + Server.Urlencode(ErrMsg)); Finally //close database connection(s), etc
End Try Or you could skip the Try Catch and put most of that code above in the Page_Error Sub so that it catches any errors on the page.
William Eaton, MCSE iTech Computer Solutions, LLC www.itechcs.com
|
|
-
11-24-2006, 4:05 PM |
-
pzycoman
-
-
-
Joined on 09-27-2006
-
London, UK
-
Posts 24
-
-
|
Re: PayPal Standard Problem...
This is where alot of people in .net come into trouble with exception handling - you should only ever handle exceptions you can deal with, and you are expecting - and handling System.Exception is a really big no no - every exception in the .net framework derives from it, so you will be catching all of them (to be honest, thats an architectural problem with the CSK) Basically, if you have an exception, you can do 3 things: - Try and recover from the exception, i.e. if your trying to write to a file and it is in use by another process, you can try again etc...
- Catch the exception, and wrap it in another exception, i.e. if you have an IO error in the ProcessPayment function, you might want to wrap it in a ProcessPaymentException (using the InnerException property) - this helps narrow down where the problem is, and alows you to bypass the horrible "catch (Exception)"
- Ignore the exception, as you cant do anything about it, and let something further up the stack deal with the error, like ASP.NET's global error handling in global.asax / HttpModules
If the querystring is wrong or non existant, then that is a non recoverable error, and the current page cant do anything about it apart from immediatly terminate execution and pass up the error.
Handling the error inside that page would be wrong, as you cannot recover from the invalid querystring. Heres a link to the ASP.NET quickstart guide on handling errors.
Senior C#.net Developer
|
|
-
11-24-2006, 5:12 PM |
-
itechcs
-
-
-
Joined on 10-21-2006
-
Indiana
-
Posts 298
-
-
|
Re: PayPal Standard Problem...
Like you said, you can't recover from the missing querystring error, so why show all that nasty runtime code to the user as the error when you can 1.) Email yourself the error details so you can troubleshoot it later, and 2.) Show the user a more friendly error message. I'm not saying that the error should be ignored, and my suggestion won't fix the problem. You and Mark identified the real problem....missing querystring values, but my suggestion simply gives a way to show a more friendly error message to the user. Sorry for not clarifying that. Also, in his code he rethrows the error....what's the point if there is nothing to "handle" the error? Yes, the exception can be handled globally, or more narrowly at the page level, or even for specific functions (like my suggestion). Bruce- The error definitely shouldn't be ignored, but I am not familiar enough with CSK/PayPal to determine if the reason the querystring values are not coming through are your fault or PayPal's.
William Eaton, MCSE iTech Computer Solutions, LLC www.itechcs.com
|
|
-
11-24-2006, 6:47 PM |
-
pzycoman
-
-
-
Joined on 09-27-2006
-
London, UK
-
Posts 24
-
-
|
Re: PayPal Standard Problem...
Application level error handlers are more than just friendly page - they provide a final place where all errors will be handled, where you can have emails sent to you on all unhandled errors. Duplication of code gets very messy, as if you need to do a simple change, you will have to track down every instance of the code, and do the change to it (DRY principle - Dont Repeat Yourself) Also, with swallowing fatal errors and showing a friendly error message, you bypass ASP.NET 2.0's WebEvents - specifically System.Web.Management.WebErrorEvent - which you can configure (via web config) to automatically email you (or insert into an sql db, if you wish) when an error occurs, and it will contain the stack trace which is vital, and other info which will be alot more useful than than just something telling you that you had an error on a certain page. You can also configure ASP.NET 2.0 to recycle your application pool if errors hit a certain threshold, which is very useful (We use it on a few of our high profile sites) By catching the exception at the page level, as opposed to at the application level, do you gain anything? You cant do anything about the exception, so you should let it bubble up higher till something above you can do something about it.
Senior C#.net Developer
|
|
-
11-24-2006, 7:31 PM |
-
itechcs
-
-
-
Joined on 10-21-2006
-
Indiana
-
Posts 298
-
-
|
Re: PayPal Standard Problem...
I was not aware of the WebErrorEvent feature. Good information pzycoman!
William Eaton, MCSE iTech Computer Solutions, LLC www.itechcs.com
|
|
-
11-27-2006, 9:41 AM |
-
Bonsai Bruce
-
-
-
Joined on 10-26-2006
-
-
Posts 29
-
-
|
Re: PayPal Standard Problem...
Folks... you've got my head spinning in circles -- this is a default installation so far... and the contents of those two files I posted are exactly as they came "out of the box!" Mark... no variables ever appear in the URL once https://www.sandbox.paypal.com/us/cgi-bin/webscr is hit, until it gets back to http://www.eranaturalbeauty.com/PayPal/PDTHandler.aspx. However, the transaction is indeed happening - I can see it in the PayPal sandbox, and the sandbox emails seem to be being sent! In checking my PayPal profile to be sure all is setup properly, I found that the Instant Payment Notification Preferences are ON and pointed at: http://www.eranaturalbeauty.com/PayPal/IPNHandler.aspx -- but when I plug that into the browser, I get the following error: Object reference not set to an instance of an object.System.NullReferenceException: Object reference not set to an instance of an object.
at IPNHandler.Page_Load(Object sender, EventArgs e) in d:\ultimaweb\bruce@ztechsystems.net\eranaturalbeauty.com\wwwroot\PayPal\IPNHandler.aspx.cs:line 19
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Under Website Payment Preferences, I have Auto Return On, and the return URL as: http://www.eranaturalbeauty.com/PayPal/PDTHandler.aspx (this provides the exact same error message as noted is my earlier message) -- also, Payment Data Transfer is On, and the Identity Token is what I'm using as my PDT ID. Encrypted Website Payments is Off, PayPal Account Optional is On and Contact Telephone Number is Off. Am I being really obtuse here, or is the PayPal Standard implementation in CSK really confusing???
~ Bruce
|
|
Page 1 of 2 (19 items)
1
|
|
|