.NETライブラリ(Omise.Net)
Omise.Netライブラリは、async/awaitパターン、LINQサポート、優れたASP.NET Core統合を備えた、Omise APIへの最新のC#インターフェースを提供します。
インストール
NuGetパッケージマネージャーの使用
dotnet add package Omise.Net
パッケージマネージャーコンソールの使用
Install-Package Omise.Net
.csprojの使用
<ItemGroup>
<PackageReference Include="Omise.Net" Version="1.0.0" />
</ItemGroup>
要件
- .NET Core 3.1+または.NET 5+、.NET 6+、.NET 7+
- C# 8.0+(nullable参照型用)
- ASP.NET Core(Webアプリケーション用)
クイックスタート
基本的な構成
using Omise;
var client = new Client(
publicKey: "pkey_test_123456789",
secretKey: "skey_test_123456789"
);
依存性注入を使用(ASP.NET Core)
// Program.csまたはStartup.cs
using Omise;
builder.Services.AddSingleton<IClient>(sp =>
new Client(
publicKey: builder.Configuration["Omise:PublicKey"],
secretKey: builder.Configuration["Omise:SecretKey"]
)
);
構成(appsettings.json)
{
"Omise": {
"PublicKey": "pkey_test_123456789",
"SecretKey": "skey_test_123456789",
"ApiVersion": "2019-05-29"
}
}
環境変数
# 開発/テスト
OMISE_SECRET_KEY=skey_test_123456789
OMISE_PUBLIC_KEY=pkey_test_123456789
# 本番環境
# OMISE_SECRET_KEY=skey_live_123456789
# OMISE_PUBLIC_KEY=pkey_live_123456789
一般的な操作
チャージの作成
using Omise;
using Omise.Models;
var client = new Client("pkey_test_123", "skey_test_123");
var request = new CreateChargeRequest
{
Amount = 100000, // 1,000.00 THB
Currency = "THB",
Card = "tokn_test_123",
Description = "注文 #1234",
Metadata = new Dictionary<string, object>
{
["order_id"] = "1234",
["customer_name"] = "John Doe"
}
};
var charge = await client.Charges.CreateAsync(request);
if (charge.Paid)
{
Console.WriteLine($"チャージ成功: {charge.Id}");
}
else
{
Console.WriteLine($"チャージ失敗: {charge.FailureMessage}");
}
レコード型を使用(C# 9.0+)
public record CreateChargeModel(
long Amount,
string Currency,
string Token,
Dictionary<string, object>? Metadata = null
);
public async Task<Charge> CreateChargeAsync(CreateChargeModel model)
{
var request = new CreateChargeRequest
{
Amount = model.Amount,
Currency = model.Currency,
Card = model.Token,
Metadata = model.Metadata ?? new Dictionary<string, object>()
};
return await _client.Charges.CreateAsync(request);
}
3Dセキュアで
public async Task<ChargeResult> CreateSecureChargeAsync(
long amount,
string token,
string returnUri)
{
var request = new CreateChargeRequest
{
Amount = amount,
Currency = "THB",
Card = token,
ReturnUri = returnUri
};
var charge = await _client.Charges.CreateAsync(request);
if (charge.Authorized)
{
if (!string.IsNullOrEmpty(charge.AuthorizeUri))
{
return new ChargeResult { RedirectUri = charge.AuthorizeUri };
}
else
{
return new ChargeResult { Success = true, Charge = charge };
}
}
throw new Exception(charge.FailureMessage);
}
チャージの取得
var charge = await client.Charges.GetAsync("chrg_test_123");
Console.WriteLine($"金額: {charge.Amount}");
Console.WriteLine($"通貨: {charge.Currency}");
Console.WriteLine($"ステータス: {charge.Status}");
Console.WriteLine($"支払い済み: {charge.Paid}");
LINQを使用したチャージのリスト表示
var request = new ListChargesRequest
{
Limit = 20,
Offset = 0,
Order = Ordering.ReverseChronological
};
var charges = await client.Charges.ListAsync(request);
var paidCharges = charges.Data
.Where(c => c.Paid)
.OrderByDescending(c => c.Created)
.ToList();
foreach (var charge in paidCharges)
{
Console.WriteLine($"{charge.Id}: {charge.Amount} {charge.Currency}");
}
顧客の作成
var request = new CreateCustomerRequest
{
Email = "customer@example.com",
Description = "John Doe",
Metadata = new Dictionary<string, object>
{
["user_id"] = "12345",
["account_type"] = "premium"
}
};
var customer = await client.Customers.CreateAsync(request);
Console.WriteLine($"顧客作成: {customer.Id}");
顧客へのカード保存
// カードトークンで顧客を更新
var updateRequest = new UpdateCustomerRequest
{
Card = "tokn_test_456"
};
var customer = await client.Customers.UpdateAsync("cust_test_123", updateRequest);
Console.WriteLine($"カード保存: {customer.DefaultCard}");
// またはカード付きで顧客を作成
var createRequest = new CreateCustomerRequest
{
Email = "customer@example.com",
Card = "tokn_test_123"
};
customer = await client.Customers.CreateAsync(createRequest);
顧客カードのリスト表示
var customer = await client.Customers.GetAsync("cust_test_123");
foreach (var card in customer.Cards.Data)
{
Console.WriteLine($"{card.Brand} 末尾 {card.LastDigits}");
Console.WriteLine($"有効期限: {card.ExpirationMonth}/{card.ExpirationYear}");
}
払い戻しの作成
// 全額返金
var refund = await client.Refunds.CreateAsync("chrg_test_123");
// 部分払い戻し
var request = new CreateRefundRequest
{
Amount = 25000, // 250.00 THB
Metadata = new Dictionary<string, object>
{
["reason"] = "customer_request",
["ticket_id"] = "TICKET-123"
}
};
refund = await client.Refunds.CreateAsync("chrg_test_123", request);
Console.WriteLine($"払い戻し {refund.Id}: {refund.Amount} {refund.Currency}");
転送の作成
var request = new CreateTransferRequest
{
Amount = 500000, // 5,000.00 THB
Recipient = "recp_test_123",
Metadata = new Dictionary<string, object>
{
["payout_id"] = "PAYOUT-456"
}
};
var transfer = await client.Transfers.CreateAsync(request);
Console.WriteLine($"転送 {transfer.Id}: {transfer.Amount}");
代替決済方法
ソースの作成
// PromptPay QR
var request = new CreateSourceRequest
{
Type = SourceType.PromptPay,
Amount = 100000,
Currency = "THB"
};
var source = await client.Sources.CreateAsync(request);
Console.WriteLine($"QR コードURL: {source.ScannableCode.Image.DownloadUri}");
// ソースを使用してチャージを作成
var chargeRequest = new CreateChargeRequest
{
Amount = 100000,
Currency = "THB",
Source = source.Id,
ReturnUri = "https://example.com/payment/callback"
};
var charge = await client.Charges.CreateAsync(chargeRequest);
インターネットバンキング
var sourceRequest = new CreateSourceRequest
{
Type = SourceType.InternetBankingSCB,
Amount = 100000,
Currency = "THB"
};
var source = await client.Sources.CreateAsync(sourceRequest);
var chargeRequest = new CreateChargeRequest
{
Amount = 100000,
Currency = "THB",
Source = source.Id,
ReturnUri = "https://example.com/payment/callback"
};
var charge = await client.Charges.CreateAsync(chargeRequest);
// charge.AuthorizeUriにリダイレクト
インストール
var sourceRequest = new CreateSourceRequest
{
Type = SourceType.InstallmentKBank,
Amount = 100000,
Currency = "THB",
InstallmentTerm = 6 // 6ヶ月
};
var source = await client.Sources.CreateAsync(sourceRequest);
var chargeRequest = new CreateChargeRequest
{
Amount = 100000,
Currency = "THB",
Source = source.Id,
ReturnUri = "https://example.com/payment/callback"
};
var charge = await client.Charges.CreateAsync(chargeRequest);
エラーハンドリング
using Omise.Exceptions;
try
{
var charge = await client.Charges.CreateAsync(request);
}
catch (OmiseException ex)
{
Console.WriteLine($"エラー: {ex.Message}");
Console.WriteLine($"ステータスコード: {ex.StatusCode}");
Console.WriteLine($"エラーコード: {ex.Code}");
switch (ex.Code)
{
case "authentication_failure":
throw new InvalidOperationException("無効なAPIキー");
case "invalid_card":
throw new InvalidOperationException("カードが拒否されました");
case "insufficient_fund":
throw new InvalidOperationException("残高不足");
default:
throw;
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"ネットワークエラー: {ex.Message}");
}
カスタムエラーハンドラー
public class PaymentErrorHandler
{
private static readonly Dictionary<string, string> ErrorMessages = new()
{
["insufficient_fund"] = "カードの残高不足",
["stolen_or_lost_card"] = "カードが盗難または紛失として報告されています",
["invalid_security_code"] = "無効なCVVコード",
["payment_cancelled"] = "支払いがキャンセルされました"
};
public static string GetErrorMessage(OmiseException ex)
{
return ErrorMessages.TryGetValue(ex.Code, out var message)
? message
: ex.Message;
}
}
ASP.NET Core統合
コントローラーの例
using Microsoft.AspNetCore.Mvc;
using Omise;
using Omise.Models;
[ApiController]
[Route("api/[controller]")]
public class PaymentController : ControllerBase
{
private readonly IClient _omiseClient;
private readonly IPaymentService _paymentService;
private readonly ILogger<PaymentController> _logger;
public PaymentController(
IClient omiseClient,
IPaymentService paymentService,
ILogger<PaymentController> logger)
{
_omiseClient = omiseClient;
_paymentService = paymentService;
_logger = logger;
}
[HttpPost("{orderId}")]
public async Task<ActionResult<ChargeResponse>> CreatePayment(
int orderId,
[FromBody] CreatePaymentRequest request)
{
try
{
var order = await _paymentService.GetOrderAsync(orderId);
if (order == null)
{
return NotFound("注文が見つかりません");
}
var chargeRequest = new CreateChargeRequest
{
Amount = (long)(order.Total * 100),
Currency = "THB",
Card = request.OmiseToken,
Description = $"注文 #{order.Id}",
Metadata = new Dictionary<string, object>
{
["order_id"] = order.Id.ToString(),
["customer_email"] = order.Email
},
ReturnUri = Url.Action(
nameof(PaymentCallback),
"Payment",
null,
Request.Scheme
)
};
var charge = await _omiseClient.Charges.CreateAsync(chargeRequest);
await _paymentService.SavePaymentAsync(new Payment
{
OrderId = order.Id,
ChargeId = charge.Id,
Amount = order.Total,
Status = charge.Status,
Paid = charge.Paid
});
if (charge.Paid)
{
await _paymentService.MarkOrderPaidAsync(order.Id);
return Ok(new ChargeResponse { Success = true, Charge = charge });
}
else if (!string.IsNullOrEmpty(charge.AuthorizeUri))
{
return Ok(new ChargeResponse { RedirectUri = charge.AuthorizeUri });
}
else
{
return BadRequest(new { Error = charge.FailureMessage });
}
}
catch (OmiseException ex)
{
_logger.LogError(ex, "支払いが失敗しました");
return StatusCode(500, new { Error = "支払いが失敗しました" });
}
}
[HttpGet("callback")]
public async Task<IActionResult> PaymentCallback([FromQuery] string id)
{
try
{
var charge = await _omiseClient.Charges.GetAsync(id);
await _paymentService.UpdatePaymentStatusAsync(charge.Id, charge.Status, charge.Paid);
if (charge.Paid)
{
return Redirect($"/orders/{charge.Metadata["order_id"]}?success=true");
}
else
{
return Redirect($"/payment?error={charge.FailureMessage}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "支払いコールバックが失敗しました");
return Redirect("/payment?error=verification_failed");
}
}
}
サービスの実装
public interface IPaymentService
{
Task<Order?> GetOrderAsync(int orderId);
Task SavePaymentAsync(Payment payment);
Task UpdatePaymentStatusAsync(string chargeId, string status, bool paid);
Task MarkOrderPaidAsync(int orderId);
}
public class PaymentService : IPaymentService
{
private readonly ApplicationDbContext _context;
private readonly IClient _omiseClient;
public PaymentService(ApplicationDbContext context, IClient omiseClient)
{
_context = context;
_omiseClient = omiseClient;
}
public async Task<Order?> GetOrderAsync(int orderId)
{
return await _context.Orders.FindAsync(orderId);
}
public async Task SavePaymentAsync(Payment payment)
{
_context.Payments.Add(payment);
await _context.SaveChangesAsync();
}
public async Task UpdatePaymentStatusAsync(string chargeId, string status, bool paid)
{
var payment = await _context.Payments
.FirstOrDefaultAsync(p => p.ChargeId == chargeId);
if (payment != null)
{
payment.Status = status;
payment.Paid = paid;
await _context.SaveChangesAsync();
}
}
public async Task MarkOrderPaidAsync(int orderId)
{
var order = await _context.Orders.FindAsync(orderId);
if (order != null)
{
order.PaymentStatus = "paid";
await _context.SaveChangesAsync();
}
}
public async Task<Charge> ChargeCustomerAsync(string customerId, decimal amount)
{
var request = new CreateChargeRequest
{
Amount = (long)(amount * 100),
Currency = "THB",
Customer = customerId
};
return await _omiseClient.Charges.CreateAsync(request);
}
public async Task<Refund> RefundChargeAsync(string chargeId, decimal? amount = null)
{
var request = amount.HasValue
? new CreateRefundRequest { Amount = (long)(amount.Value * 100) }
: null;
return await _omiseClient.Refunds.CreateAsync(chargeId, request);
}
}
バックグラウンドサービス
using Microsoft.Extensions.Hosting;
public class SubscriptionChargeService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<SubscriptionChargeService> _logger;
public SubscriptionChargeService(
IServiceProvider serviceProvider,
ILogger<SubscriptionChargeService> logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await ChargeSubscriptionsAsync();
await Task.Delay(TimeSpan.FromHours(24), stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "サブスクリプション課金エラー");
}
}
}
private async Task ChargeSubscriptionsAsync()
{
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var omiseClient = scope.ServiceProvider.GetRequiredService<IClient>();
var subscriptions = await context.Subscriptions
.Where(s => s.Status == "active")
.ToListAsync();
foreach (var subscription in subscriptions)
{
try
{
var request = new CreateChargeRequest
{
Amount = subscription.PlanAmount,
Currency = "THB",
Customer = subscription.CustomerId,
Description = $"サブスクリプション {DateTime.Now:MMMM yyyy}"
};
var charge = await omiseClient.Charges.CreateAsync(request);
if (charge.Paid)
{
subscription.LastChargeDate = DateTime.UtcNow;
await context.SaveChangesAsync();
}
}
catch (OmiseException ex)
{
_logger.LogError(ex, "サブスクリプション {SubscriptionId} の課金失敗", subscription.Id);
}
}
}
}
// Program.csに登録
builder.Services.AddHostedService<SubscriptionChargeService>();