首页 > 解决方案 > 为什么通过 jQuery Ajax 将 Plaid 链接结果发布到 ASP.NET MVC 控制器时缺少属性数据?

问题描述

我的网站可以使用 Plaid 创建链接令牌,但是每当我尝试将此数据发送回服务器时,都会丢失一些数据。

这是我的 .csthml 文件

    @section scripts_upper
{
    <!-- Include the Plaid Link initialize script on each page of your site. -->
    <!-- It should always be loaded directly from https://cdn.plaid.com, rather -->
    <!-- than included in a bundle or hosted yourself. -->
    <script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
}

@model SS.PFS.WebApp.Models.PlaidLinkResults

@{
    ViewBag.Title = "Link";
}
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <h2>Link</h2>
    <p>
        LinkToken:  @ViewBag.LinkToken
    </p>
    <p>
        Accesstoken:  @ViewBag.Accesstoken
    </p>

    <div class="col-md-offset-2 col-md-10">
        <input type="button" value="Link" onclick="launchPlaid()" class="btn btn-default" />
    </div>


    <label>Plaid Public Token</label>
    <br>
    <p id='plaidToken'></p>
    <BR>
    <label>MetaData</label>
    <br>
<textarea id='plaidMetadata2' rows='30' cols='100'></textarea>

}

@section scripts
{

    <script>

        function launchPlaid() {
            const handler = Plaid.create({
                //token: document.getElementById('linkToken').value,
                token:  '@ViewBag.LinkToken',
                // The onSuccess() function of the Plaid plugin will return a public
                // token and metadata object to your code. Please use our API to send
                // us the public token, and we will query the routing number and account
                // number of the bank account from Plaid and store it securely on our systems.
                onSuccess: (public_token, metadata) => {
                    document.getElementById('plaidToken').innerHTML = public_token;
                    document.getElementById('plaidMetadata2').value = JSON.stringify(metadata, null, 2);
                    //testPost(JSON.stringify(metadata, null, 2));
                   // testPost(metadata);
                    testPost(JSON.stringify(metadata));
                    return true;
                },
                onLoad: () => {  },
                onExit: (err, metadata) => {
                    document.getElementById('plaidToken').innerHTML = err;
                    document.getElementById('plaidMetadata2').value = JSON.stringify(metadata, null, 2);
                },
                onEvent: (eventName, metadata) => {  },
                receivedRedirectUri: null,
            });
            // Calling open() will display the "Institution Select" view to your user,
            // starting the Link flow.
            handler.open();
        }


        function testPost(valueToPost) {

            $.ajax({
                type: "POST",
                url: "/BankAccount/Link",
                data: '{ results: ' + valueToPost+ '}',
             //  data: valueToPost,
                //contentType: "application/json; charset=utf-8",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (response) {
                    alert("Hello: " + response.Name + " .\nCurrent Date and Time: " + response.DateTime);
                },
                failure: function (response) {
                    alert('failure:  ' + response.responseText);
                },
                error: function (response) {
                    //alert('error:  ' + response.responseText);
                    //document.getElementById('plaidMetadata2').value = response.responseText;
                    document.getElementById('plaidMetadata2').value =  valueToPost;
                }
            });
        }
    </script>
}

这是 /BankAccount/Link 控制器/动作

[HttpPost]
    public async Task<ActionResult> Link(Models.PlaidLinkResults results)
    {
        var resultsetToSaveAsLinkedAccounts = results;
        return View("Index");
    }

我可以看到填充的数据,因为最终结果显示在 plaidMetadata2 中。它包含 Accounts 的值,但机构->Id、LinkSessionId 和 PublicToken 等属性为空。帐户也有一些数据。

这是来自浏览器调试工具的数据示例 在此处输入图像描述

服务器上的数据截图

这是 PlaidLinkResults 模型

using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace SS.PFS.WebApp.Models
{
    public class PlaidLinkResults
    {
        [JsonProperty("institution") ]
        public Acklann.Plaid.Entity.Institution Institution { get; set; }

        public Acklann.Plaid.Entity.Account Account { get; set; }

        public string AccountId { get; set; }

        public List<Acklann.Plaid.Entity.Account> Accounts { get; set; }

        [JsonProperty("link_session_id")]
        public string LinkSessionId { get; set; }

        [JsonProperty("public_token")]
        public string PublicToken { get; set; }
    }
}

这是机构模型的代码

using Acklann.Plaid.Institution;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Acklann.Plaid.Entity
{
    /// <summary>
    /// Represents a banking institution.
    /// </summary>
    public class Institution
    {
        /// <summary>
        /// Gets or sets the identifier.
        /// </summary>
        /// <value>The identifier.</value>
        [JsonProperty("institution_id")]
        public string Id { get; set; }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        [JsonProperty("name")]
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this instance has Multi-Factor Authentication.
        /// </summary>
        /// <value><c>true</c> if this instance has Multi-Factor Authentication; otherwise, <c>false</c>.</value>
        [JsonProperty("has_mfa")]
        public bool HasMfa { get; set; }

        /// <summary>
        /// Gets or sets the Multi-Factor Authentication selections.
        /// </summary>
        /// <value>The mfa selections.</value>
        [JsonProperty("mfa")]
        public string[] MfaSelections { get; set; }

        [JsonProperty("mfa_code_type")]
        public string MfaType { get; set; }

        /// <summary>
        /// Gets or sets the hexadecimal representation of the primary color used by the institution.
        /// </summary>
        [JsonProperty("primary_color")]
        public string PrimaryColor { get; set; }

        /// <summary>
        /// Gets or sets the Base64 encoded representation of the institution's logo.
        /// </summary>
        [JsonProperty("logo")]
        public string Logo { get; set; }

        /// <summary>
        /// Gets or sets the URL for the institution's website.
        /// </summary>
        /// <value>
        /// The URL.
        /// </value>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// Gets or sets the credentials.
        /// </summary>
        /// <value>The credentials.</value>
        [JsonProperty("credentials")]
        public Credential[] Credentials { get; set; }

        /// <summary>
        /// Gets or sets the products.
        /// </summary>
        /// <value>The products.</value>
        [JsonProperty("products")]
        public string[] Products { get; set; }

        /// <summary>
        /// Gets or sets the country codes using the ISO-3166-1 alpha-2 country code standard.
        /// </summary>
        /// <value>
        /// The countries.
        /// </value>
        [JsonProperty("country_codes")]
        public string[] Countries { get; set; }

        /// <summary>
        /// Gets or sets the information about the institution's current status.
        /// </summary>
        [JsonProperty("status")]
        public StatusSchema Status { get; set; }

        /// <summary>
        /// Represents an <see cref="Institution"/> login credentials.
        /// </summary>
        public struct Credential
        {
            /// <summary>
            /// Gets or sets the label.
            /// </summary>
            /// <value>The label.</value>
            [JsonProperty("label")]
            public string Label { get; set; }

            /// <summary>
            /// Gets or sets the name.
            /// </summary>
            /// <value>The name.</value>
            [JsonProperty("name")]
            public string Name { get; set; }

            /// <summary>
            /// Gets or sets the type of the data.
            /// </summary>
            /// <value>The type of the data.</value>
            [JsonProperty("type")]
            public string DataType { get; set; }
        }

        public class StatusSchema
        {
            /// <summary>
            /// Gets or sets status information regarding Item adds via Link.
            /// </summary>
            [JsonProperty("item_logins")]
            public InstitutionStatus ItemLogin { get; set; }

            /// <summary>
            /// Gets or sets the status information regarding transactions updates.
            /// </summary>
            [JsonProperty("transactions_updates")]
            public InstitutionStatus Transactions { get; set; }

            /// <summary>
            /// Gets or sets the status information regarding Auth requests..
            /// </summary>
            /// <value>
            /// The authentication.
            /// </value>
            [JsonProperty("auth")]
            public InstitutionStatus Auth { get; set; }

            /// <summary>
            /// Gets or sets the status information regarding Balance requests.
            /// </summary>
            /// <value>
            /// The balance.
            /// </value>
            [JsonProperty("balacne")]
            public InstitutionStatus Balance { get; set; }

            /// <summary>
            /// Gets or sets the status information regarding Identity requests.
            /// </summary>
            [JsonProperty("identity")]
            public InstitutionStatus Identity { get; set; }
        }
    }
}

标签: jqueryajaxasp.net-mvcpostplaid

解决方案


大多数情况下发生这种情况是因为发送了格式错误的数据。

注意到您如何格式化要发送的数据的一些问题导致您的 JSON 格式不正确。

请注意该results字段如何没有引号

因为您尝试自己构建字符串

//...

data: '{ results: ' + valueToPost+ '}',

//...

然后模型绑定器的任务是尝试从格式错误的有效负载中推断出所需的数据并将它们映射到模型。

我首先建议只是将元数据传递给testPost按原样运行

//...
onSuccess: (public_token, metadata) => {

  //...

  testPost(metadata);
  return true;
},
//...

并让该函数处理格式。

function testPost(valueToPost) {
    var data = { results : valueToPost }; //creating payload object
    $.ajax({
        type: "POST",
        url: "/BankAccount/Link",
        data: JSON.stringify(data), //formatting to JSON here
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            alert("Hello: " + response.Name + " .\nCurrent Date and Time: " + response.DateTime);
        },
        failure: function (response) {
            alert('failure:  ' + response.responseText);
        },
        error: function (response) {
            //alert('error:  ' + response.responseText);
            //document.getElementById('plaidMetadata2').value = response.responseText;
            document.getElementById('plaidMetadata2').value =  valueToPost;
        }
    });
}

该操作还应该明确告诉模型绑定器在哪里查找数据

[HttpPost]
public ActionResult Link([FromBody]Models.PlaidLinkResults results) {
    var resultsetToSaveAsLinkedAccounts = results;
    return View("Index");
}

这样它就不必从可能的来源之一推断数据


推荐阅读