开发者

Injecting infra layer interface in app service

I have two aggregates, Advertiser and Payment.

I am using Paypal and Authorize.net payment gateway. So i created interface in infra layer.

interface IPaymentMethod
{
   void ProcessPayment(PaymentInfo paymentInfo);
}

and implemented it again in infra layer.

Public class PaypalPaymentGateway : IPaymentMethod
{
    public void ProcessPayment(PaymentInfo paymentInfo)
    {
        // call Paypa开发者_开发问答l api and pass paymentinfo
    }
}

//same for authorize.net payment gateway Below is my app service class

public class PaymentGatewayService : IPaymentGatewayService
{

    IPaypalMethod paypalMethod;

    public PaymentGatewayService(IPaypalMethod paypalMethod)
    {            
        this.paypalMethod = paypalMethod;
        if (paypalMethod == null)
          throw new Exception("PaypalMethod not initialized");
    }

     public void DepositFundInAdvertiser
       (PaymentInfo paymentInfo, RegistrationID advertiserRegistrationID)
     {
        if (paymentMethod != null)            
            throw new Exception("PaymentMethod empty.");

        PaymentResult paymentResult= 
          paymentMethod.ProcessPayment(paymentInfo);
        Advertiser advertiser = advertiserRepository
          .Find(advertiserRegistrationID);
        advertiser.AddAdvertiserFund(paymentInfo.PaymentTotal);
        advertiserRepository.Save(advertiser);
    }
}

In App layer - can I inject PaypalMethod interface in App layer constructor and do the following in DepositFundInAdvertiser method?

Remember IPaypalMethod is created and implemented in infra layer.


Your approach seems good enough.

Only I would define IPayer abstraction inside domain layer instead of infrastructure layer.

Because it's (most likely) responsibility of domain model to decide how to react if payment is [un]successful.

//in domain model
public class IPayer{
  bool Pay(Money amountToBePaid, BankAccount account);;
}
public class Payment{
  public void Pay(IPayer payer){
   EnsurePaymentCanBePaid();
   IsPaid=payer.Pay(AmountToBePaid,Account);
   if(!IsPaid) throw new Exception("Payment failed!");
  }
}
//in infrastructure layer
public class PayPalPayer:IPayer{
  public bool Pay(Money amountToBePaid, BankAccount account){
    //bla bla
  }
}


To follow up on my comment. I would also put the PaymentService in infrastructure layer as an infrastructure service. But as Arnis said you should also reflect ho the model respond to this action - Pay.

I (not sure) would probably have some kind of PaymentService in applicaion service layer that works with both entities Advertiser and Payment (through IAdvertiserRepository and IPaymentRepository injected through constructor).

In method (writing this method in memcode): PaymentService.PayAdvert(Advertiser advertiser, Advert advert, Payment paymentInfo) { advertiser.BuyAdvertising(AdvertPayment.Create(advert,paymentInfo)) }

BuyAdvertising method takes both Advert and Payment into AdvertPayment class (which has a static create method for ctor itself. This class can be handy if you want a PaymentHistory collection for Advertiser that contains AdvertPayments in date order. But BuyAdvertising raises a domain event BuyAdvertisingEvent that triggers a eventhandler in application layer, BuyAdvertisingEventHandler.

This Eventhandler has your IPaypalGatewayService injected in constructor. With the event we have Payment info. If Payment is a success the EventHandler can also have IAdvertiserRepository injected in ctor and save the AdvertPayment into Advertiser payment history collection.

then BuyAdvertising can determine the outcome of payment transaction by checking if advert is paid and added to history collection.

I hope you get the picture. This way you have several tools like an event which is declared in domain model and triggered from the entity advertiser. The model takes action and you have moved out the infra tech logic against PayPal through DomainEventHandler an still, you have not located the logic entirely in application layer. The control is in the domain, but details that domain don't care about is placed in infra layer.

My experience is that these scenarios are common for me and you usually go the easy way, letting the application service do all talking to infralayer. But then you're closingin on a anemic model design, because what is left for the model to do? Just validation properties? Just managing aggregates and collections? I think there is more to it. It should also contains a lot of entity action methods (I call them so... :)) like BuyAdvertisment.

/Cheers

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜