Creating a generic payments library - c#

I am trying to create Payment Gateway abstraction, for one of my projects using Asp.Net Core, so that clients can integrate their payment gateways, by creating derived libraries. My application will load the derived libraries and call the methods.
Below is an interface that all payment gateways must implement. This lies in the Core library, let's call it PaymentGateway.Core.dll. This library is part of the main application.
namespace PaymentGateway.Core
{
public interface IPaymentGateway
{
string Name { get; }
// The purpose of this function is to transform the order details into an object,
// as expected by the underlying gateway's apis
object CreatePaymentRequest(Order request);
// The purpose of this function is to transform the payment response object,
// received from the payment gateway api,
// into an application entity that represents this payment.
Payment ProcessPaymentResponse(object response);
}
// Order for which the payment to be collected. This entity is stored in DB
public class Order
{
string UserId { get; set; }
string ProductId { get; set; }
double OrderTotal { get; set; }
}
// A payment attempted for an Order. This entity is stored in DB
public class Payment
{
Order Order { get; set; }
string PaymentGateway { get; set; }
double Amount { get; set; }
PaymentStatus Status { get; set; } // Failed, User Aborted, Success
}
}
Below is an example of PayPal integration library, let's call it PaymentGateway.PayPal.dll. This library references the core library and implements the PaymentGateway interface.
namespace PaymentGateway.PayPal
{
class PayPal : IPaymentGateway
{
public string Name { get => "PayPal"; }
public object CreatePaymentRequest(Order request)
{
:
:
}
public Payment ProcessPaymentResponse(object response)
{
:
:
}
}
}
The process flow in the core library to execute a payment would be like :
The buyer clicks on the PayPal button on the webpage.
The core application then initializes the PayPal object.
The core application then calls the CreatePaymentrequest() function with the order details. The function will transform the order details into PayPal Payment Request format.
The returned data is passed to PayPal apis to initiate a transaction.
After PayPal api finishes, it returns the response in a its defined format.
The response from PayPal api is passed to the server, which calls ProcessPaymentResponse() on the PayPal object. This function transform the response into Payment object.
The problem i have is that the application ( Core ) doesn't understand the return type of CreatePaymentRequest(), as it is depends on the called gateway. Similarly, for ProcessPaymentResponse() the argument type is gateway specific and the type will be defined in the gateway library.
For now i am forced to use System.Object. Is there any better solution to the problem ?

public interface IPaymentGateway<T> where T : class
{
string Name { get; }
T CreatePaymentRequest(PaymentRequest request);
PaymentResponse ProcessPaymentResponse(T response);
}
public class PayPal<T> : IPaymentGateway<T> where T : class
{
public string Name { get; }
public T CreatePaymentRequest(PaymentRequest request)
{
throw new NotImplementedException();
}
public PaymentResponse ProcessPaymentResponse(T response)
{
throw new NotImplementedException();
}
}
public class Example
{
public void ExampleMethod()
{
IPaymentGateway<Foo> paypal = new PayPal<Foo>();
var name = paypal.Name;
Foo paymentRequest = paypal.CreatePaymentRequest(new PaymentRequest());
var paymentResponse = paypal.ProcessPaymentResponse(new Foo());
}
}
public class Foo
{
}
public class PaymentResponse
{
}
public class PaymentRequest
{
}
Instead of returning an object why not make it generic and have them pass in the type?

Related

consume JSON from webhook in C#

Hi I'm looking to create a simple webhook receiver and dump the data into a table.
This is for receiving SMS using Zipwhip. Zipwhip will send a post with JSON.
Need to receive the JSON and process.
What is a simple way to accomplish this.
Thanks in advance.
In ServiceStack your callback would just need to match the shape of your Response DTO, e.g:
[Route("/path/to/callback")]
public class CorpNotes
{
public int Departments { get; set; }
public string Note { get; set; }
public DateTime WeekEnding { get; set; }
}
// Example of OrmLite POCO Data Model
public class MyTable {}
public class MyServices : Service
{
public object Any(CorpNotes request)
{
//...
Db.Insert(request.ConvertTo<MyTable>());
}
}
Example uses Auto Mapping Utils to populate your OrmLite POCO datamodel, you may want to do additional processing before saving the data model.
If the callback can send arbitrary JSON Responses in the payload you can use an object property to accept arbitrary JSON however we'd recommend using Typed DTOs wherever possible.
This can be what the receiving method in your controller can look like on the receiving side. Make sure that your receiving and sending json object match.
[HttpPost]
[Route("Edit")]
public JsonResult Edit([FromBody] CorpNotes newMessage)
{return Json(TotalWeekNoteSearch);}
public class CorpNotes
{
public int Departments { get; set; }
public string Note { get; set; }
public DateTime WeekEnding { get; set; }
}
I am actually working on a .net project receiving Json from a Angular front end, so this should be the same concept. Also make sure that what you are receiving is truly a workable object such as.
{Departments: 4, Note: "This is notes 2020Q1W13", WeekEnding: "2020-01-25T00:00:00"}
Also try looking into this example which would be helpful in regards to webhooks.
public class MyWebHookHandler : WebHookHandler
{
public MyWebHookHandler()
{
this.Receiver = "custom";
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
CustomNotifications notifications = context.GetDataOrDefault<CustomNotifications>();
foreach (var notification in notifications.Notifications)
{
...
}
return Task.FromResult(true);
}
}
The type of the data is typically JSON or HTML form data, but it is possible to cast to a more specific type if desired.

Make .NET WebApi service deserialize recieved JSON as child object

The system i am developing is using DataContractJsonSerializer.
The service looks like this:
[HttpPost, Route("RunQuery")]
public List<BIResultRecord> RunQuery(BIQuery query) {
// Logic
}
The BIQuery class hierarchy is as follows:
[DataContract]
[KnownType(typeof(BIQuery1))]
public class BIQuery
{
[DataMember]
public string Member { get; set; }
[DataMember]
public QueryTypeEnum QueryType { get; set; }
}
[DataContract]
public class BIQuery1 : BIQuery
{
public BIQuery1()
{
QueryType = QueryTypeEnum.Type1;
}
[DataMember]
public ClassSpecificObject Object { get; set; }
}
THE PROBLEM:
Although i am sending BIQuery1 as a json object it is always deserialized (in my RunQuery method) as the parent object (BIQuery).
WHAT I'VE TRIED:
I've removed the default formatter and added a new one:
public class DataContractJsonFormatter : JsonMediaTypeFormatter
{
public override DataContractJsonSerializer CreateDataContractSerializer(Type type)
{
return new DataContractJsonSerializer(type, new DataContractJsonSerializerSettings() { EmitTypeInformation = EmitTypeInformation.AsNeeded });
}
}
I serialized the object in .NET to see the JSON structure and
cloning it to the request. I saw that it adds
"__type" : "BIQuery1"
to the JSON, which i'm using as well and it changed nothing.
Please help!
MORE DETAILS
The .NET system (client and server) runs in production as is, so only minor changes currently allowed. I'm making also a web client that would work with the existing services over REST.
[HttpPost, Route("RunQuery")]
public List<BIResultRecord> RunQuery(BIQuery query) {
// Logic
}
Your argument in the RunQuery method is the of type BIQuery object. It is deserializing as a BIQuery object because that is the type you are telling the method it will be passed. If you are passing an object of the type BIQuery1 to the method, do this instead:
[HttpPost, Route("RunQuery")]
public List<BIResultRecord> RunQuery(BIQuery1 query) {
// Logic
}

How to implement Delete service call using ServiceStack

I have couple of questions related to REST service implementation using ServiceStack.
For GET operation, I define my request DTO as below :
[Route("/Customer/{ID}", Verbs = "GET")]
public class GetCustomer : IReturn<GetCustomerResponse>
{
....
....
}
Here "GetCustomer" is request DTO and "GetCustomerResponse" is response DTO. But for PUT/POST/DELETE operation, I just need to know whether operation got committed successfully or not and if 'not' then what is the exception. So what should be my request dto definition for POST/PUT/DELETE? Should it use IReturnVoid as shown below?
[Route("/Customer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturnVoid
{
....
....
}
If I have to use IReturnVoid then how I can retrieve any exception information that might occur on committing my operation?
In the error handling document for service stack it is written and I quote below
Error Response Types
The Error Response that gets returned when an Exception is thrown
varies on whether a conventionally-named {RequestDto}Response DTO
exists or not.
If it exists:
The {RequestDto}Response is returned, regardless of the service
method's response type. If the {RequestDto}Response DTO has a
ResponseStatus property, it is populated otherwise no ResponseStatus
will be returned. (If you have decorated the {ResponseDto}Response
class and properties with [DataContract]/[DataMember] attributes, then
ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus
property.
The Service Clients transparently handles the different Error Response
types, and for schema-less formats like JSON/JSV/etc there's no actual
visible difference between returning a ResponseStatus in a custom or
generic ErrorResponse - as they both output the same response on the
wire.
What I'm not getting from above is what should be the return type for my Delete method in my service implementation? How I can implement my delete method without defining delete response DTO but yet I'm able to retrieve 'ErrorResponse' n exception info?
Is it possible to define route with "DELETE" verb? I have following implementation.
Route:
[Route("/DeleteCustomer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturn<DeleteCustomerResponse>
{
public int ID { get; set; }
}
Method implementation:
public DeleteContactResponse Delete(DeleteContact request)
{
.....
}
But whenever I call this delete using my client, I always get "NotFound" exception. I tried different clients but with all I get 404 error.
One of the reference link available alongwith Servicestack document reuses the "GET" and "DELETE" verb together.
Another link suggests not all browsers support delete operation.
So I wonder how Delete operation should be implemented?
See this earlier answer for details on how to design a REST-ful API with ServiceStack.
The CustomerRestExample contains a complete stand-alone example of a Customer REST ServiceStack Service:
Customer Service Definition
Here's an example of the custom Routes and Request DTO's of what a typical Customer REST Service could look like:
[Route("/customers", "GET")]
public class GetCustomers : IReturn<GetCustomersResponse> {}
public class GetCustomersResponse
{
public List<Customer> Results { get; set; }
}
[Route("/customers/{Id}", "GET")]
public class GetCustomer : IReturn<Customer>
{
public int Id { get; set; }
}
[Route("/customers", "POST")]
public class CreateCustomer : IReturn<Customer>
{
public string Name { get; set; }
}
[Route("/customers/{Id}", "PUT")]
public class UpdateCustomer : IReturn<Customer>
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/customers/{Id}", "DELETE")]
public class DeleteCustomer : IReturnVoid
{
public int Id { get; set; }
}
OrmLite POCO Model:
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
Essentially the Custom Routes identify the Resource whilst the HTTP VERB indicates the operation on that Resource. Looking at the HTTP Requests makes this a little clearer:
GET /customers -> return all Customers
POST /customers -> Create a new Customer
GET /customers/1 -> return Customer 1
PUT /customers/1 -> Update Customer 1
DELETE /customers/1 -> Delete Customer 1
Customer Service Implementation
With the above DTO's definitions in-place, we can now implement this Customer REST Service by adding an implementation for each Request DTO - in this example using OrmLite:
public class CustomerService : Service
{
public object Get(GetCustomers request)
{
return new GetCustomersResponse { Results = Db.Select<Customer>() };
}
public object Get(GetCustomer request)
{
return Db.SingleById<Customer>(request.Id);
}
public object Post(CreateCustomer request)
{
var customer = new Customer { Name = request.Name };
Db.Save(customer);
return customer;
}
public object Put(UpdateCustomer request)
{
var customer = Db.SingleById<Customer>(request.Id);
if (customer == null)
throw HttpError.NotFound("Customer '{0}' does not exist".Fmt(request.Id));
customer.Name = request.Name;
Db.Update(customer);
return customer;
}
public void Delete(DeleteCustomer request)
{
Db.DeleteById<Customer>(request.Id);
}
}
Customer Usage Example
With the above Customer REST Service implementation, we can re-use the Request DTO's with ServiceStack's .NET Service Clients to provide an end-to-end Typed API without code-gen, i.e:
var client = new JsonServiceClient(BaseUri);
//GET /customers
var all = client.Get(new GetCustomers()); // Count = 0
//POST /customers
var customer = client.Post(new CreateCustomer { Name = "Foo" });
//GET /customer/1
customer = client.Get(new GetCustomer { Id = customer.Id }); // Name = Foo
//GET /customers
all = client.Get(new GetCustomers()); // Count = 1
//PUT /customers/1
customer = client.Put(
new UpdateCustomer { Id = customer.Id, Name = "Bar" }); // Name = Bar
//DELETE /customers/1
client.Delete(new DeleteCustomer { Id = customer.Id });
//GET /customers
all = client.Get(new GetCustomers()); // Count = 0
The comments above include the HTTP Operations performed in each Service Client example.
I got the fix for my 2nd question from following two links :
1. Link1
2. Link2
I don't fully understand this fix but doing above changes worked for me and now I can call Delete function from any clients.
For 1st question, pls refer #mythz 's reply below in detail.

ODataConventionModelBuilder with inherited entities

I've an WebAPI OData v3 interface using ODataConventionModelBuilder. It contains some entities which are inherited, and also a model which has a collection of the abstract object:
public abstract class BaseObject
{
[Key]
public int Id { get; set; }
[ForeignKey("Object3")]
public int? ParentId { get; set; }
public virtual Object3 Parent { get; set; }
}
public class Object1: BaseObject
{
}
public class Object2: BaseObject
{
}
public class Object3
{
[Key]
public int Id { get; set; }
public ICollection<BaseObject> MyObjects { get; set; }
}
I'm calling the interface using Breeze with client side metadata, using expand:
http://example.com/api/Object3?$expand=MyObjects
The server response looks like this:
{
"odata.type":"MyNamespace.Object1",
"odata.id":"http://example.com/api/BaseObject(1)",
"Parent#odata.navigationLinkUrl":"http://example.com/api/BaseObject(1)/Parent",
"Id":1,
"ParentId":1
}
Breeze now recognizes this as an entity of type Object1. But if I modify the entity and save the changes it makes a POST request to http://example.com/api/BaseObject(1). To being able to handle the different concrete types I need the POST request to go to the specific controller http://example.com/api/Object(1).
What do I need to change so that Breeze makes to update POST calls to the concrete controller and not the controller of the base object?
UPDATE: After inspecting the Breeze source code, it seems like Breeze uses the odata.id as URI for the POST request. Is it somehow possible to have the OData API return the URI for the concrete object as odata.id instead of the base object?
I got this working with a nasty hack by removing extraMetadata from all entities before saving with breeze:
var entities = manager.getEntities(null, breeze.EntityState.Modified);
for (var i = 0; i < entities.length; i++) {
delete entities[i].entityAspect.extraMetadata;
}
It there are no extraMetadata (which contains the odata.id) are available, breeze calculates the URI to the controller of the concrete model.
I don't know if there's a better solution available, that the OData API sends the correct odata.id in the first place.

How to get the request object from wcf message?

I have a WCf service with Contracts shown below.
[MessageContract]
public class ServiceRequest
{
[MessageBodyMember]
public int RequestId { get; set; }
[MessageBodyMember]
public OrderDetails OrderDetails { get; set; }
}
[DataContract]
public class OrderDetails
{
[IsLogRequired]
public int OrderId { get; set; }
[IsLogRequired]
public int Quantity { get; set; }
public string CustomerName { get; set; }
}
[IsLogRequired] is custom Attribute.
We need to get all properties in the request which have "[IsLogRequired]" attribute when the request is received. We want to do it as generic solution so that it can be plugged into all services.
We thought of using "MessageInspector" to do this implementing "IDispatchMessageInspector".
How do i get the actual request object from "System.ServiceModel.Channels.Message" parameter of IDispatchMessageInspector.AfterReceiveRequest() method?
Please correct me if i am using a wrong interface or wrong method. Any other solution to this?
I am assuming that "[IsLogRequired] is custom property." means a custom attribute...
Simple answer is that there is no solution to transfer custom attributes that are decorating the data contract as you described it.
Data contracts should be pure and not encumbered by business logic. The know how about the what should be done with various fields belongs to a service implementation.
Possible approach could look like this:
public class OrderService : IOrderService
{
private void ProcessOrder(Order order)
{
var ra = new AuditMetadataResourceAccess();
MethodInfo[] fieldsToLog = ra.GetLoggingFields(typeof(OrderDetal));
if (fieldsToLog.Any())
{
var logger = new LogingEngine();
logger.Log(fieldsToLog, order.OrderDetails);
}
}
}
You could move this implementation inside message inspector or operation invoker. Carlos Figueira has extensive description of each WCF extensibility point.
"How do i get the actual request object from "System.ServiceModel.Channels.Message" parameter of IDispatchMessageInspector.AfterReceiveRequest() method?"
I am assuming you are referring to Web request. WebOperationContext.Current but you need to have ASP.NET Compatibility Mode turned on.

Categories