{"id":1002,"date":"2013-09-20T01:13:07","date_gmt":"2013-09-19T15:13:07","guid":{"rendered":"http:\/\/ntsblog.homedev.com.au\/?p=1002"},"modified":"2014-08-14T00:57:59","modified_gmt":"2014-08-13T14:57:59","slug":"paypalmerchantsdk-integrate-paypal-mvc-4-website","status":"publish","type":"post","link":"https:\/\/ntsblog.homedev.com.au\/index.php\/2013\/09\/20\/paypalmerchantsdk-integrate-paypal-mvc-4-website\/","title":{"rendered":"PayPalMerchantSDK, integrate paypal into your mvc 4 website"},"content":{"rendered":"<div id=\"ntsbl-3546567669\" class=\"ntsbl-before-content ntsbl-entity-placement\"><script async src=\"\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js?client=ca-pub-6288941070289539\" crossorigin=\"anonymous\"><\/script><ins class=\"adsbygoogle\" style=\"display:inline-block;width:728px;height:90px;\" \ndata-ad-client=\"ca-pub-6288941070289539\" \ndata-ad-slot=\"9356781486\"><\/ins> \n<script> \n(adsbygoogle = window.adsbygoogle || []).push({}); \n<\/script>\n<\/div><p>The following outlines some of the things that I have learned whilst trying to integrate a PayPal payment gateway into the MVC 4.0 website.<\/p>\n<h2>Installation<\/h2>\n<p>After much reading I determined that I easiest way was to use the PayPaylMerchantSDK.<br \/>\nThis is implemented using the PayPal classic API which is the only API available in Australia @ the time of writing.<br \/>\nThe easiest way to add this to your application is to use NuGet in Visual Studio (Tools ->> Library Package Manager ->> Manage NuGet Packages for Visual Studio) and search for PayPal.<br \/>\nClick on the PayPalMerchantSDK and choose Install. This will download the dependencies including log4net and the &#8220;PayPal Core SDK for .Net&#8221;<\/p>\n<h2>Code Samples<\/h2>\n<p>You should download and use the &#8220;Merchant&#8221; solution in the .net code samples that can be found here.<br \/>\n<a href=\"https:\/\/github.com\/paypal\/codesamples-dotnet\" target=\"_blank\">Classic API .Net code samples<\/a><\/p>\n<h2>App.Config<\/h2>\n<p>The code samples have an App.Config file that contains the base configuration for working with the API.<br \/>\nIt contains the log4net and PayPal configuration section. You should copy these configuration sections into your web.config file.<\/p>\n<h2>Access the paypal settings section in the web.config<\/h2>\n<p>When coding I want to access some of the PayPal settings that I just copied into my web.config file, for example &#8220;paypalUrl&#8221; could be used when attempting to send a request for express checkout.<\/p>\n<p>To access the paypal configuration settings that are in the web.config use the following code:<\/p>\n<p>[csharp]<br \/>\n  string url = PayPal.Manager.ConfigManager.Instance.GetProperties()[&quot;paypalUrl&quot;];<br \/>\n[\/csharp]<\/p>\n<h2>IPN Testing<\/h2>\n<p><a href=\"https:\/\/developer.paypal.com\/webapps\/developer\/applications\/ipn_simulator\" target=\"_blank\">IPN Simulator<\/a><\/p>\n<p>I thought that it was dangerous opening port 80 through the firewall to get to my development server, so I was clever and used an unusual port number. This worked fine for most things but the IPN testing would not work with my special port number.<\/p>\n<p>You have to use port 80 to allow the IPN test to work.<\/p>\n<h3>Core .SDK<\/h3>\n<p>The old way of implementing the IPN callback has been integrated into the PayPal .Core SDK.<br \/>\n<a href=\"https:\/\/github.com\/paypal\/sdk-core-dotnet\/blob\/master\/IPNMessage.cs\" target=\"_blank\">IPNMessage.cs<\/a><\/p>\n<p>This can now be implemented in 3 lines of code.<\/p>\n<p>Put this inside your controller page<\/p>\n<p>[csharp]<br \/>\npublic ActionResult IPN()<br \/>\n{<br \/>\n\tbyte[] bytes = Request.BinaryRead(Request.ContentLength);<\/p>\n<p>\tPayPal.IPNMessage message = new PayPal.IPNMessage(bytes);<br \/>\n\tif (message.Validate())<br \/>\n\t{<br \/>\n\t\t\/\/ message returned VERIFIED<br \/>\n\t}<br \/>\n\telse<br \/>\n\t{<br \/>\n\t\t\/\/ There was a problem<br \/>\n\t}<\/p>\n<p>\treturn null;<br \/>\n}<br \/>\n[\/csharp]<\/p>\n<p>Note I then created a PayPalTransaction Class to simplify access to the PayPal.IPNMessage object.<\/p>\n<p>It looked something like this.<br \/>\n[csharp]<br \/>\npublic class PayPalTransaction<br \/>\n    {<\/p>\n<p>        #region Constants<\/p>\n<p>        private const string KEY_ADDRESSSTATE = &quot;address_state&quot;;<br \/>\n        private const string KEY_TXNID = &quot;txn_id&quot;;<br \/>\n        private const string KEY_LASTNAME = &quot;last_name&quot;;<br \/>\n        private const string KEY_CURRENCY = &quot;mc_currency&quot;;<br \/>\n        private const string KEY_PAYERSTATUS = &quot;payer_status&quot;;<br \/>\n        private const string KEY_ADDRESSSTATUS = &quot;address_status&quot;;<br \/>\n        private const string KEY_TAX = &quot;tax&quot;;<br \/>\n        private const string KEY_INVOICE = &quot;invoice&quot;;<br \/>\n        private const string KEY_PAYEREMAIL = &quot;payer_email&quot;;<br \/>\n        private const string KEY_FIRSTNAME = &quot;first_name&quot;;<br \/>\n        private const string KEY_BUSINESS = &quot;business&quot;;<br \/>\n        private const string KEY_VERIFYSIGN = &quot;verify_sign&quot;;<br \/>\n        private const string KEY_PAYERID = &quot;payer_id&quot;;<br \/>\n        private const string KEY_PAYMENTDATE = &quot;payment_date&quot;;<br \/>\n        private const string KEY_PAYMENTSTATUS = &quot;payment_status&quot;;<br \/>\n        private const string KEY_RECEIVEREMAIL = &quot;receiver_email&quot;;<br \/>\n        private const string KEY_PAYMENTTYPE = &quot;payment_type&quot;;<br \/>\n        private const string KEY_ADDRESSNAME = &quot;address_name&quot;;<br \/>\n        private const string KEY_ADDRESSSTREET = &quot;address_street&quot;;<br \/>\n        private const string KEY_ADDRESSZIP = &quot;address_zip&quot;;<br \/>\n        private const string KEY_ADDRESSCITY = &quot;address_city&quot;;<br \/>\n        private const string KEY_ADDRESSCOUNTRY = &quot;address_country&quot;;<br \/>\n        private const string KEY_ADDRESSCOUNTRYCODE = &quot;address_country_code&quot;;<br \/>\n        private const string KEY_SHIPPING = &quot;mc_shipping&quot;;<br \/>\n        private const string KEY_ITEMNUMBER1 = &quot;item_number1&quot;;<br \/>\n        private const string KEY_SHIPPING1 = &quot;mc_shipping1&quot;;<br \/>\n        private const string KEY_ITEMNAME1 = &quot;item_name1&quot;;<br \/>\n        private const string KEY_HANDLING1 = &quot;mc_handling1&quot;;<br \/>\n        private const string KEY_GROSS1 = &quot;mc_gross1&quot;;<br \/>\n        private const string KEY_GROSS = &quot;mc_gross&quot;;<br \/>\n        private const string KEY_FEE = &quot;mc_fee&quot;;<br \/>\n        private const string KEY_RESIDENCECOUNTRY = &quot;residence_country&quot;;<br \/>\n        private const string KEY_NOTIFYVERSION = &quot;notify_version&quot;;<br \/>\n        private const string KEY_RECEIVERID = &quot;receiver_id&quot;;<br \/>\n        private const string KEY_HANDLING = &quot;mc_handling&quot;;<br \/>\n        private const string KEY_TXNTYPE = &quot;txn_type&quot;;<br \/>\n        private const string KEY_CUSTOM = &quot;custom&quot;;<br \/>\n        private const string KEY_TESTIPN = &quot;test_ipn&quot;;<\/p>\n<p>        private const string KEY_IPNTRACKID = &quot;ipn_track_id&quot;;<br \/>\n        private const string KEY_PROTECTION_ELIGIBILITY = &quot;protection_eligibility&quot;;<\/p>\n<p>        private const string KEY_QUANTITY = &quot;quantity&quot;;<br \/>\n        private const string KEY_RESEND = &quot;resend&quot;;<br \/>\n        private const string KEY_NOTIFY_VERSION = &quot;notify_version&quot;;<\/p>\n<p>        #endregion <\/p>\n<p>        #region Constructor<\/p>\n<p>        public PayPalTransaction()<br \/>\n        {<br \/>\n        }<\/p>\n<p>        public PayPalTransaction(PayPal.IPNMessage message)<br \/>\n        {<br \/>\n            this.TransactionId = message.IpnValue(KEY_TXNID);<br \/>\n            this.TransactionType = message.IpnValue(KEY_TXNTYPE);<br \/>\n            this.PayerId = message.IpnValue(KEY_PAYERID);<br \/>\n            this.Currency = message.IpnValue(KEY_CURRENCY);<br \/>\n            this.Custom = message.IpnValue(KEY_CUSTOM);<br \/>\n            this.HandlingAmount = GetAsDecimal(message, KEY_HANDLING);<br \/>\n            this.FirstName = message.IpnValue(KEY_FIRSTNAME);<br \/>\n            this.IpnTrackId = message.IpnValue(KEY_IPNTRACKID);<br \/>\n            this.LastName = message.IpnValue(KEY_LASTNAME);<br \/>\n            this.PayerStatus = message.IpnValue(KEY_PAYERSTATUS);<br \/>\n            this.PaymentDate = GetAsDate(message, KEY_PAYMENTDATE);<br \/>\n            this.PaymentStatus = message.IpnValue(KEY_PAYMENTSTATUS);<br \/>\n            this.ProtectionEligibility = message.IpnValue(KEY_PROTECTION_ELIGIBILITY);<br \/>\n            this.ShippingAmount = GetAsDecimal(message, KEY_SHIPPING);<br \/>\n            this.GrossAmount = GetAsDecimal(message, KEY_GROSS);<br \/>\n            this.FeeAmount = GetAsDecimal(message, KEY_FEE);<\/p>\n<p>            this.Quantity = GetAsInt(message, KEY_QUANTITY);<br \/>\n            this.Resend = GetAsBool(message, KEY_RESEND);<br \/>\n            this.PaymentType = message.IpnValue(KEY_PAYMENTTYPE);<br \/>\n            this.NotifyVersion = message.IpnValue(KEY_NOTIFY_VERSION);<br \/>\n            this.PayerEmail = message.IpnValue(KEY_PAYEREMAIL);<br \/>\n            this.TaxAmount = GetAsDecimal(message, KEY_TAX);<br \/>\n            this.ResidenceCountry = message.IpnValue(KEY_RESIDENCECOUNTRY);<\/p>\n<p>            this.ItemNumber1 = message.IpnValue(KEY_ITEMNUMBER1);<br \/>\n            this.ItemName1 = message.IpnValue(KEY_ITEMNAME1);<br \/>\n            this.ShippingAmount1 = GetAsDecimal(message, KEY_SHIPPING1);<br \/>\n            this.HandlingAmount1 = GetAsDecimal(message, KEY_HANDLING1);<br \/>\n            this.GrossAmount1 = GetAsDecimal(message, KEY_GROSS1);<\/p>\n<p>            this.AddressCity = message.IpnValue(KEY_ADDRESSCITY);<br \/>\n            this.AddressCountryCode = message.IpnValue(KEY_ADDRESSCOUNTRYCODE);<br \/>\n            this.AddressCountry = message.IpnValue(KEY_ADDRESSCOUNTRY);<br \/>\n            this.AddressName = message.IpnValue(KEY_ADDRESSNAME);<br \/>\n            this.AddressStreet = message.IpnValue(KEY_ADDRESSSTREET);<br \/>\n            this.AddressZip = message.IpnValue(KEY_ADDRESSZIP);<\/p>\n<p>        }<\/p>\n<p>        #endregion<\/p>\n<p>        #region Private Helpers<\/p>\n<p>        private int GetAsInt(PayPal.IPNMessage m, string key)<br \/>\n        {<br \/>\n            int value = Convert.ToInt32(m.IpnValue(key));<br \/>\n            return value;<br \/>\n        }<\/p>\n<p>        private bool GetAsBool(PayPal.IPNMessage m, string key)<br \/>\n        {<br \/>\n            bool bln = false;<br \/>\n            string value = m.IpnValue(key);<br \/>\n            if (value != null)<br \/>\n            {<br \/>\n                bln = (value.ToLower().Trim() == &quot;true&quot;);<br \/>\n            }<br \/>\n            return bln;<br \/>\n        }<\/p>\n<p>        private decimal GetAsDecimal(PayPal.IPNMessage m, string key)<br \/>\n        {<br \/>\n            decimal value = Convert.ToDecimal(m.IpnValue(key));<br \/>\n            return value;<br \/>\n        }<\/p>\n<p>        private DateTime GetAsDate(PayPal.IPNMessage m, string key)<br \/>\n        {<br \/>\n            string value = m.IpnValue(key);<br \/>\n            value = HttpUtility.HtmlDecode(value);<\/p>\n<p>            int iPos = value.LastIndexOf(&quot; &quot;);<br \/>\n            string timezone = value.Substring(iPos+1);<br \/>\n            TimeZoneInfo tzSource = null;<\/p>\n<p>            value = value.Substring(0, iPos);<\/p>\n<p>            switch (timezone)<br \/>\n            {<br \/>\n                case &quot;PST&quot;:<br \/>\n                case &quot;PDT&quot;:<br \/>\n                    tzSource = TimeZoneInfo.FindSystemTimeZoneById(&quot;Pacific Standard Time&quot;);<br \/>\n                    break;<br \/>\n            }<\/p>\n<p>            DateTime date = Convert.ToDateTime(value);<br \/>\n            date = TimeZoneInfo.ConvertTimeToUtc(date, tzSource);<br \/>\n            date = TimeZoneInfo.ConvertTimeFromUtc(date, TimeZoneInfo.Local);<\/p>\n<p>            return date;<br \/>\n        }<\/p>\n<p>        #endregion<\/p>\n<p>        #region Properties<\/p>\n<p>        public int Id { get; set; }<\/p>\n<p>        \/\/\/ &lt;summary&gt;<br \/>\n        \/\/\/ The transaction Id of the PayPal Transaction<br \/>\n        \/\/\/ &lt;\/summary&gt;<br \/>\n        public string TransactionId { get; private set; }<\/p>\n<p>        public string TransactionType { get; private set; }<\/p>\n<p>        public string PayerId { get; private set; }<\/p>\n<p>        public string IpnTrackId { get; private set; }<\/p>\n<p>        public string Currency { get; private set; }<\/p>\n<p>        public string Custom { get; private set; }<\/p>\n<p>        public string FirstName { get; private set; }<\/p>\n<p>        public decimal HandlingAmount { get; private set; }<\/p>\n<p>        public string LastName { get; private set; }<\/p>\n<p>        public string ProtectionEligibility { get; private set; }<\/p>\n<p>        public string PayerStatus { get; private set; }<\/p>\n<p>        public DateTime PaymentDate { get; private set; }<\/p>\n<p>        public string PaymentStatus { get; private set; }<\/p>\n<p>        public int Quantity { get; private set; }<\/p>\n<p>        public bool Resend { get; private set; }<\/p>\n<p>        public string PaymentType { get; private set; }<\/p>\n<p>        public string NotifyVersion { get; private set; }<\/p>\n<p>        public string PayerEmail { get; private set; }<\/p>\n<p>        public string ResidenceCountry { get; private set; }<\/p>\n<p>        public string AddressName { get; private set; }<\/p>\n<p>        public string AddressStreet { get; private set; }<\/p>\n<p>        public string AddressZip { get; private set; }<\/p>\n<p>        public string AddressCity { get; private set; }<\/p>\n<p>        public string AddressCountry { get; private set; }<\/p>\n<p>        public string AddressCountryCode { get; private set; }<\/p>\n<p>        public decimal ShippingAmount { get; private set; }<\/p>\n<p>        public decimal GrossAmount { get; private set; }<\/p>\n<p>        public decimal FeeAmount { get; private set; }<\/p>\n<p>        public decimal TaxAmount { get; private set; }<\/p>\n<p>        public decimal ShippingAmount1 { get; private set; }<\/p>\n<p>        public decimal GrossAmount1 { get; private set; }<\/p>\n<p>        public decimal HandlingAmount1 { get; private set; }<\/p>\n<p>        public string ItemNumber1 { get; private set; }<\/p>\n<p>        public string ItemName1 { get; private set; }<\/p>\n<p>        #endregion<\/p>\n<p>        #region Virtual Properites<\/p>\n<p>        public virtual bool IsComplete<br \/>\n        {<br \/>\n            get<br \/>\n            {<br \/>\n                bool value = (this.PaymentStatus.ToLower().Trim() == &quot;completed&quot;);<br \/>\n                return value;<br \/>\n            }<br \/>\n        }<br \/>\n        #endregion<\/p>\n<p>    }<br \/>\n[\/csharp]<\/p>\n<p>[csharp][\/csharp]<\/p>\n<h2>Links<\/h2>\n<ul>\n<li><a href=\"http:\/\/paypal.github.io\/sample-apps\/\" target=\"_blank\">Code Samples<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/paypal\/codesamples-dotnet\" target=\"_blank\">.Net Merchant Samples<\/a> Just click to download the entire thing as a zip file<\/li>\n<ul>\n","protected":false},"excerpt":{"rendered":"<p>The following outlines some of the things that I have learned whilst trying to integrate a PayPal payment gateway into the MVC 4.0 website. Installation [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[5,6],"tags":[],"class_list":["post-1002","post","type-post","status-publish","format-standard","hentry","category-c","category-code"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/posts\/1002","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/comments?post=1002"}],"version-history":[{"count":0,"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/posts\/1002\/revisions"}],"wp:attachment":[{"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/media?parent=1002"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/categories?post=1002"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ntsblog.homedev.com.au\/index.php\/wp-json\/wp\/v2\/tags?post=1002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}