首先,讓我解釋一下為什么我認為我需要一個單例。我正在將多個 Hosted Checkout 支付處理器集成到我的 Blazor Server 應用程式中。它們都按以下方式作業;
Index.razor有一個顯示支付處理器 url 的 iframe。- 當客戶完成付款時,iframe 會重定向回我的應用程式指定的 url
PaymentComplete.razor,.PaymentComplete.razor使用范圍服務HostedCheckoutService來引發Index.razor包含支付回應的事件。
這就是問題所在。PaymentComplete.razor托管在iframe內,因此使用單獨的范圍進行處理。HostedCheckoutService從內部引發的任何屬性更改或事件都PaymentComplete.razor不會是Index.razor. 這使得(幾乎?)不可能將 iframe 內的資訊合并到Index.razor.
顯然解決這個問題的方法是注冊HostedCheckoutService為單例。現在的問題是,當一個客戶端從 引發一個事件時PaymentComplete.razor,所有客戶端都必須處理它。
為了解決這個問題,我創建了IndexBase一個名為EventTargetId. 當 iframe 支付完成后,回傳的 urlPaymentComplete.razor將包含EventTargetId查詢字串中的 。
索引庫.cs
<iframe style="width:100%;height:50vh" src="@HostedCheckoutFrameSrc " frameborder="0" ></iframe>
public class IndexBase : ComponentBase, IDisposable
{
[Inject] NavigationManager NavigationManager { get; set; }
[Inject] HostedCheckoutService HostedCheckoutService { get; set; }
[Inject] PaymentApi PaymentApi { get; set; }
public string HostedCheckoutFrameSrc { get; set; }
public string EventTargetId { get; set; } = Guid.NewGuid().ToString();
protected override void OnInitialized()
{
HostedCheckoutService.OnPaymentComplete = PaymentComplete;
}
public void Dispose()
{
HostedCheckoutService.OnPaymentComplete -= PaymentComplete;
}
private void PaymentComplete(string eventTargetId, string paymentJson)
{
// Hosted checkout iframe has returned a successfull payment.
// Do something, send order, notification, ect.
}
public async Task InitializePayment()
{
string returnUrl = NavigationManager.BaseUri $"/PaymentComplete?eventTargetId={EventTargetId}";
InitializePaymentResponse response = await PaymentApi.CreatePaymentRequest(returnUrl);
// Set iframe src property to third party payment providers url.
// When customer completes third party payment url, the iframe redirects to PaymentComplete.razor (returnUrl).
HostedCheckoutFrameSrc = PaymentApi.baseUrl response.PaymentId;
}
}
PaymentComplete.razor(從第三方 url 重定向,托管在 iframe 中)
此頁面將從EventTargetId查詢字串中獲取 并在我們的單例服務上引發一個事件。
[Inject] NavigationManager NavigationManager { get; set; }
[Inject] PostFormService PostFormService { get; set; }
[Inject] HostedCheckoutService HostedCheckoutService { get; set; }
protected override async Task OnInitializedAsync()
{
// We face double render problem, but Form values will be null on secord render anyways.
if (PostFormService.Form != null)
{
NavigationManager.TryGetQueryString<string>("eventTargetId", out string eventTargetId);
string paymentJson = PostFormService.Form?["PaymentResponse"];
HostedCheckoutService.PaymentCompleted(eventTargetId, paymentJson);
}
}
在我的單例HostedCheckoutService中,我使用EventTargetId.
public class HostedCheckoutService
{
public event Action<string, string> OnPaymentComplete;
public void PaymentCompleted(string eventTargetId, string paymentJson)
{
// Instead of raising the event for every instance attached to this action
// only raise the event for the specified target.
var instance = OnPaymentComplete.GetInvocationList()
.Where(d => d.Target is IndexBase && ((IndexBase)d.Target).EventTargetId == eventTargetId)
.FirstOrDefault();
instance?.DynamicInvoke(eventTargetId, paymentJson);
}
}
最后,問題!這似乎是對單例事件的不可接受的使用,還是有人有更好的方法?即使每個客戶端都不會處理該事件,呼叫GetInvocationList()仍將包含每個訂閱類的串列。
注意:每個事件訂閱者實際上并不是一個完整的IndexBase類。這將是一個簡單的支付組件(我簡化了這個例子)。
uj5u.com熱心網友回復:
我主要關心的是在事件中呼叫所有已注冊的方法。
因為我不知道還有什么作用,所以擁有一個包含針對操作的簡單 Guid 集合的HostedCheckoutService單例怎么樣- 可能還有注冊時間來操作超時系統。PaymentTransactionServiceIndex 呼叫一個Register方法PaymentTransactionService來注冊它的 Guid 和它的 Action。——而且明明是一個ReRegister方法當它Disposes。 PaymentComplete在 上呼叫TransactionComplete方法PaymentTransactionService。它檢查它的串列并執行注冊的操作(如果有) - 如果沒有則記錄錯誤。您還可以使用每個PaymentComplete呼叫來啟動一個檢查超時和洗掉過期注冊的管理例程。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/483902.html
標籤:C# asp.net 核心 西装外套 blazor 服务器端
上一篇:如何使用剃須刀頁面取消系結屬性
