dev

GPWebpayNet – A .NET Library for Communication With GP Webpay Payment Gateway

Overview

In these days we are interconnecting multiple services into our information systems. When we are deciding which service we will integrate, except the functionality, pricing, etc., an important aspect is ease of integration. The service should contain some documentation, but support such as SDK or package for as the most popular languages should be available too.

This is not exactly the case of GP Webpay. They provide documentation for their solution. But for example a documentation for HTTP API is from year 2016. There is no SDK or source code example, except sample code for evaluation that our implementation of calculation of digest (a hash calculated from request data) is returning valid value. These samples do nothing more. Another thing is that C# code sample is written .NET 3.5. Really, in 2018. But in newer version of .NET and especially with .NETCore, interfaces changed. So it is quite obsolete.

As I mentioned, document describing how the request should be created, signed, etc., is provided. There is funny sentence that implementation will take three days in average. Ok, but if they provide some SDK, it can take few hours. Next, when the GP Webpay change their protocol, they can just provide new SDK version so consumers can update their code very simply. Without any inspection of internals.

So when I was implementing communication with this gateway, I extracted the code and created a library.

Library Description

Library supports following .NET versions:

  • Full .NET Framework 4.6.1
  • .netstandart 1.6
  • .netstandart 2.0

Use Cases

You can use is together with WebAPI and SPA of with ASP MVC. It is up to you.

The base GP webpay process (simplified) is as follows:

  1. Generate payment request
  2. Send it via GET or POST go payment gateway
  3. Process GET request from GP webpay

The process with API and SPA is as follows:

  1. SPA send order request to API
  2. API generates payment request for GET (url) and sends it back to SPA
  3. SPA use url and redirects to it
  4. GP webpay send request to API
  5. API process request and redirect to SPA with corresponding result

The process with MVC is as follows:

  1. Send request to MVC
  2. MVC generates payment request for GET/POST and redirects to GP webpay
  3. GP webpay send request to MVC
  4. MVC process request and redirect to SPA with corresponding result

Project Structure

GPWebpayNet.Example

It contains examples how to use this SDK. For more details you can check GPWebpayNet.SDK.Spec too.

GPWebpayNet.SDK

The main project. The main project class is GPWebpayNet.Sdk.Services.ClientService that provides methods needed for payment process. Other classes are used by this class. Whole project is designed to be used with some IoC framework so classes are decoupled.

GPWebpayNet.Example

It contains SDK unit tests.

Usage Samples

Get Redirect URL for Payment Request

public string GetRedirectUrl()
{
  var loggerFactory = new LoggerFactory().AddConsole();

  const string url = Constants.GPWebpayUrlTest;
  const string privateCertificateFile = "certs/test.pfx";
  const string privateCertificateFilePassword = "test";
  const string publicCertificateFile = "certs/test.pfx";
  const string publicCertificateFilePassword = "test";
  var doc = new XmlDocument();
  doc.AppendChild(doc.CreateElement("Info"));

  var request = new PaymentRequest
  {
    MerchantNumber = "235235",
    OrderNumber = 2412,
    Amount = new decimal(64.6546),
    Currency = CurrencyCodeEnum.Eur,
    DepositFlag = 1,
    MerOrderNumber = "MerOrderNumber",
    Url = "https://www.example.org",
    Description = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
    MD = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
    PaymentMethod = PaymentMethodEnum.Mps,
    DisabledPaymentMethod = PaymentMethodEnum.Crd,
    PaymentMethods = new[] {PaymentMethodEnum.Mcm, PaymentMethodEnum.NotSet},
    Email = "user@example.org",
    ReferenceNumber = "77987",
    AddInfo = doc.DocumentElement,
    Lang = "CZ"
  };

  var encodingLogger = loggerFactory.CreateLogger();
  var clientServiceLogger = loggerFactory.CreateLogger();
  var clientService = new ClientService(new EncodingService(encodingLogger),
  new PaymentRequestTransformer(), new PaymentResponseTransformer(), clientServiceLogger);				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			>clientServiceLogger);

  return clientService.GenerateGPWebPayRedirectUrl(
    url,
    request,
    privateCertificateFile,
    privateCertificateFilePassword,
    publicCertificateFile,
    publicCertificateFilePassword);
}

Process Incomming GP webpay request

public void ProcessIncommingGPWPRequest()
{
  var loggerFactory = new LoggerFactory().AddConsole();

  // Args from Request object
  var queryArgs = new QueryCollection(new Dictionary()
  {
    {"OPERATION", new StringValues("Operation")},
    {"ORDERNUMBER", new StringValues("12332")},
    {"PRCODE", new StringValues("0")},
    {"SRCODE", new StringValues("0")},
    {"RESULTTEXT", new StringValues("ResultText")},
    {"USERPARAM1", new StringValues("UserParam1")},
    {"DIGEST", new StringValues("Digest")},
    {"DIGEST1", new StringValues("Digest1")},
  });

  const string publicCertificateFile = "certs/test.pfx";
  const string password = "test";

  var encodingLogger = loggerFactory.CreateLogger();
  var clientServiceLogger = loggerFactory.CreateLogger();
  var clientService = new ClientService(new EncodingService(encodingLogger),
  new PaymentRequestTransformer(), new PaymentResponseTransformer(), clientServiceLogger);

  // Service will creates PaymentResponse from incomming args and validate response digest with
  // public certificate provided by GPWP and then check if "PRCODE" and "SRCODE" values have correct or error values
  // ReSharper disable once UnusedVariable
  var paymentResponse = clientService.ProcessGPWebPayResponse(queryArgs, publicCertificateFile, password);
}

That’s all – two methods. Yes, you should read how the process and communication with the gateway works, but it is really not important to know how exactly the protocol, especially creation of message, is done if you really do not need it – which is exactly this case. So GP webpay, do it. You will have more satisfied customers.

Where To Get It

You can find NuGet package here. Just add it to your project:

PM> Install-Package GPWebpayNet.Sdk

Or clone in on GitHub.

You can of course support this project too :).

 

Advertisement
dev

Deploying Azure Webjobs With the Same Name Within Different App Services Instances

Deploying single project within different Azure App Services can be a common task – one service for test, one service for prelife and another one for production. There is no problem with such scenario. But when you are using Webjobs project, it can cause an issue.

Webjobs are using Storage for various purposes. You must specify AzureWebJobsDashboard and AzureWebJobsStorage connection strings in Webjob configuration.

If you are deploying same project with Webjobs within a different App Service, you MUST SET CONNECTION STRINGS TO DIFFERENT STORAGE ACCOUNT. Otherwise these Webjobs will collide – they will access same metadata because of the same path name. E.g., in case of time-triggered WebJob it can happen that only the first WebJob will be executed periodically and the seconds one never.

Note: There is opened GitHub issue that is still open because of low priority.