Recently, I blogged about a PayPal Subscriptions project I was working on. This was a website where people could subscribe via PayPal for weekly religious lessons under one of three user categories. The previous post looked at the differences between the Web Site and Web Application Project models and what this meant when attempting to implement user profiles in conjunction with the membership system. Since I had previously created a few basic E-Commerce websites with regular Buy-Now buttons, I thought this would be a breeze... wrong :-|
As part of the project requirements, there would be separate, weekly messages displayed to the subscribers. The first message of a yearly subscription that would be displayed, would be tied to the original subscription date. No matter what kind of subscription system or periodical you are publishing, at some stage you will need to offer the correct issue number to a given subscriber. Since everyone will be subscribing at different times, this means keeping count! I decided to keep a tab of the week numbers. Bear in mind, that week calculations are done differently in different cultures and there is not a bug if you see week number 53!
using System.Globalization;
CultureInfo cultInfo = CultureInfo.CurrentCulture;
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now,
cultInfo.DateTimeFormat.CalendarWeekRule,
cultInfo.DateTimeFormat.FirstDayOfWeek);
For the task in hand, I used ASP.NET 2.0 and C# with VS 2005 and SQL Server 2005. It was built as a Web Application Project, which meant using the Web Profile Builder wrapper class to enable access to user profiles. I've heard of several people getting errors with this but it worked for me out of the box. I'm inclined to think that some may have overlooked a particular section of the documentation which I am going to repeat here:
"When your project has reloaded, you need to generate the web profile class and manually include it in your project. Use the solution explorer to do this. In the solution explorer, choose the “Show All Files” option and press the “Refresh” button two times. The first time will generate the profile class and WebProfileBuilder.user file. The second time will actually show the files now that they exist. To include the generated profile class, right-click on the generated profile class and choose “Include In Project”. Now you will be able to write code against the profile class."
The rest is pretty straightforward:
public partial class MyClass : System.Web.UI.Page
{
private WebProfile Profile
{
get
{
return new WebProfile(Context.Profile);
}
}
protected void Page_Load(object sender, EventArgs e)
{
string subscriberID = Profile.subscriberID;
string subscriberGroup = Profile.subscriberGroup;
}
...
}
Of course, the glue that holds the entire application together is the IPN class. I had previously used the freely-available IPN class from XDev Software. Note that this class is designed for regular PayPal transactions. I had to customize it to handle PayPal subscriptions. All you really have to do is pare it down to handle only the subscription-related variables you are handling on the return handshake from PayPal. The following set of return variables worked for my particular scenario; you will set these as properties of your custom IPN class:
string txn_type;
string business;
string item_name;
string payment_gross;
string payment_status;
string receiver_email;
string payer_email;
string pending_reason;
string payment_date;
string subscribe_id;
string first_name;
string last_name;
string custom;
Here's an overview of a typical subscription Web application life-cycle:
1) User subscribes on your site and is directed to the PayPal site where they pay
2) Your IPN class handshakes with PayPal and grabs the values returned by PayPal
3) Your IPN class updates your application database and generates an email to the subscriber with a return URL to register on your site
4) Your IPN class generates an email (backup) to the merchant with the subscription data
5) The subscriber creates a user account on your site and you set up any extra member info you want to store in their profile
protected void Createuserwizard1_CreatingUser(object sender, EventArgs e)
{
WebProfile p = WebProfile.GetProfile(CreateUserWizard1.UserName, true);
p.Initialize(CreateUserWizard1.UserName, true);
p.subscriberID = ViewState["SubscriberID"].ToString();
p.subscriberGroup = ViewState["Group"].ToString();
p.Save();
}
Some Gotchas:
Do not use a return URL from PayPal
Do not mix IPN and PDT. IPN is all you need
Do not forget the Save() method when creating the profile :-S