首页 > 解决方案 > 从 asp.net razor 视图调用 ajax 请求

问题描述

如何从以 JSON 格式返回数据的 razor 视图发起 ajax 请求(调用控制器操作)?

在我的剃刀视图中单击操作链接后,该页面执行发布请求,该请求将页面重定向到 /actionName 当然不存在。

我也在使用 jQuery,但如果我使用 jQuery ajax 方法,我不确定如何从 razor 视图中获取需要传递的数据。

ShowEventLogs.cshtml

@{ ViewBag.Title = "Event Logs"; }
@model IEnumerable
<Application.Models.EventLogs>
<table id="data-table" class="table display responsive" style="width:100%">
   <thead class="thead-colored thead-light">
      <tr>
         <th>Time</th>
         <th>Scheme</th>
         <th>Serial Number</th>
         <th>Batch</th>
         <th>Exp Date</th>
         <th>Product Code</th>
         <th>Http Code</th>
         <th>Is Confirmed?</th>
         <th>Confirmation Date</th>
         <th>Verify Pack</th>
      </tr>
   </thead>
   <tbody>
      @foreach (var item in Model)
      {
      <tr>
         <td>@item.Timestamp</td>
         <td>@item.ProductCodeScheme</td>
         <td>@item.SerialNumber</td>
         <td>@item.Batch</td>
         <td>@item.ExpirationDate</td>
         <td>@item.ProductCode</td>
         <td>@item.HttpResponseCode</td>
         <td>@item.ConfirmedParsed</td>
         <td>@item.ConfirmedDate</td>
         if (@item.HttpResponseCode == "202")
         {
         <td class="text-secondary">@Html.ActionLink("Verify Pack", "VerifyPack", "Home", new { ProductCodeScheme = @item.ProductCodeScheme, ProductCode = @item.ProductCode, SerialNumber = @item.SerialNumber, Batch = @item.Batch, ExpirationDate = @item.ExpirationDate, CommandStatusCode = 0 }, new { @class = "text-info" })</td>
         }
         else
         {
         <td class="text-secondary">Not Available</td>
         }
      </tr>
      }
   </tbody>
</table>
}

控制器动作

[HttpPost]
public ActionResult VerifyPack(string productCodeScheme, string productCode, string serialNumber, string batch, string expirationDate, int commandStatusCode, string orderTrackingNo = null) {
    string TextAreaResult = string.Empty;
    string TextAreaResultException = string.Empty;
    string TextAreaResultHttpOperationCode = string.Empty;
    string TextAreaResultHttpResponseCode = string.Empty;
    string TextAreaResultHttpInformation = string.Empty;
    string TextAreaResultHttpWarning = string.Empty;
    string TextAreaResultState = string.Empty;
    string RemoteIpAddress = string.Format("{0}", Request.UserHostAddress);

    try {
        using(SecureMediDatabase database = new SecureMediDatabase(this)) {
            DatabaseFactory.setDatabase(database);
            Request baseRequest = (Request) database.createRequest(Country);
            ServiceThread serviceThread = new ServiceThread(0, null, Country);
            serviceThread.attach(this);

            baseRequest.setId(0);
            baseRequest.setProductCodeScheme(productCodeScheme);
            baseRequest.setRequestType(1); //single pack
            baseRequest.setProductCode(productCode);
            baseRequest.setSerialNumber(serialNumber);
            baseRequest.setBatch(batch);
            baseRequest.setExpirationDate(expirationDate);
            baseRequest.setWorkstation(RemoteIpAddress);
            baseRequest.setManualEntry(string.IsNullOrEmpty(expirationDate) || string.IsNullOrEmpty(batch));

            if (baseRequest.isManualEntry()) {
                switch (commandStatusCode) {
                    case 2:
                    case 3:
                        break;

                    default:
                        throw new NotSupportedException("This operation does not support manual entries!");
                }
            }

            switch (Country) {
                case "SE":
                    SecureMediRequestSE requestSE = (SecureMediRequestSE) baseRequest;
                    requestSE.setUserId(@User.Identity.Name);
                    requestSE.setCommandStatusCode(commandStatusCode);
                    requestSE.OrderTrackingNumber = orderTrackingNo;
                    break;

                case "FI":
                    SecureMediRequestFI requestFI = (SecureMediRequestFI) baseRequest;
                    requestFI.setSubUserId(@User.Identity.Name);
                    break;
            }

            serviceThread.RunRequest(control, baseRequest, apteekki);

            TextAreaResult = string.Format("{0} {1} {2} {3} {4}", baseRequest.getResponseOperationCode(), baseRequest.getHttpResponseCode(), baseRequest.getHttpInformation(), baseRequest.getHttpWarning(), baseRequest.getResponseStatusCode());

            TextAreaResultHttpOperationCode = string.Format("{0}", baseRequest.getResponseOperationCode());

            TextAreaResultHttpResponseCode = string.Format("{0}", baseRequest.getHttpResponseCode());

            TextAreaResultHttpInformation = string.Format("{0}", baseRequest.getHttpInformation());

            TextAreaResultHttpWarning = string.Format("{0}", baseRequest.getHttpWarning());

            TextAreaResultState = string.Format("{0}", baseRequest.getResponseStatusCode());
        }
    } catch (Exception exc) {
        TextAreaResultException = "Exception: " + exc.Message;
    }

    return Json(new {
        result = TextAreaResult,
        httpOperationCode = TextAreaResultHttpOperationCode,
        httpResponseCode = TextAreaResultHttpResponseCode,
        httpInformation = TextAreaResultHttpInformation,
        httpWarning = TextAreaResultHttpWarning,
        state = TextAreaResultState,
        exception = TextAreaResultException,
        isSuccess = TextAreaResultHttpResponseCode == "200" || TextAreaResultHttpResponseCode == "202"
    });
}

基于答案的错误:

在此处输入图像描述 在此处输入图像描述

标签: c#jqueryasp.net-mvcrazormodel-view-controller

解决方案


基本上,@Html.ActionLink()助手使用属性呈现锚标记 ( <a>),并默认通过刷新整个页面来使用 GET 请求,因此您需要添加preventDefault()才能使用该元素的 AJAX 回调。如果 action 方法使用 HTTP GET 方法,您可以对锚链接的公共类执行简单的 AJAX 调用,如下所示:

$('.text-info').on('click', function (e) {
    e.preventDefault();

    var url = $(this).attr('href');
    $.get(url, function (response) {
        // do something with AJAX response
    });
});

但是,由于目标控制器操作标记为[HttpPost],因此您需要从href具有附加功能的属性中提取查询字符串参数,并通过设置在 AJAX 调用中使用它们type: 'POST',或者使用$.post()

$('.text-info').on('click', function (e) {
    e.preventDefault(); // mandatory to prevent GET request

    var url = $(this).attr('href');

    var pcs = getQueryStringParams(url, 'ProductCodeScheme');
    var pc = getQueryStringParams(url, 'ProductCode');
    var sn = getQueryStringParams(url, 'SerialNumber');
    var batch = getQueryStringParams(url, 'Batch');
    var expDate = getQueryStringParams(url, 'ExpirationDate');
    var csc = getQueryStringParams(url, 'CommandStatusCode');

    // create key-value pair for action method parameters
    var obj = { ProductCodeScheme: pcs, ProductCode: pc, SerialNumber: sn, ... }

    $.ajax({
        type: 'POST',
        url: url.split('?')[0], // URL without query string, or use '@Url.Action("VerifyPack", "Home")'
        data: obj,
        dataType: 'json', // expects response as JSON
        success: function (response) {
            // do something with AJAX response
        },
        error: function (xhr, status, err) {
            // error handling
        }
    });

    // just make sure that the link is not redirecting
    return false;
});

function getQueryStringParams(url, name) {
     return (RegExp(name + '=' + '(.+?)(&|$)').exec(url)||[,null])[1];
}

实际上存在另一种从锚标记调用 AJAX 的方法,例如@Ajax.ActionLink(),具体取决于您的选择:

@Ajax.ActionLink("Verify Pack", "VerifyPack", "Home", new { ProductCodeScheme = @item.ProductCodeScheme, ProductCode = @item.ProductCode, SerialNumber = @item.SerialNumber, Batch = @item.Batch, ExpirationDate = @item.ExpirationDate, CommandStatusCode = 0 }, 
                 new AjaxOptions { HttpMethod = "POST", 
                                   InsertionMode = InsertionMode.Replace, 
                                   UpdateTargetId = "targetElementId", 
                                   OnComplete = "onComplete();" 
                                 },
                 new { @class = "text-info" })

笔记:

如果您需要处理来自同一控制器的 AJAX 请求和普通请求,您可以使用Request.IsAjaxRequest()(或Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"在 Core MVC 中)区分它们。


推荐阅读