【问题标题】:Calling ajax request from asp.net razor view从 asp.net razor 视图调用 ajax 请求
【发布时间】:2019-06-10 01:12:15
【问题描述】:

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

在我的 razor 视图中单击操作链接后,页面会发出将页面重定向到 /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"
    });
}

基于答案的错误:

【问题讨论】:

  • 您必须自己创建锚标签,而不是 Html.ActionLink,然后使用 javascript 添加一个不显眼的 onclick。在您的点击处理程序中,您将不得不手动将 URL 构建到 get,然后执行您的 $.ajax
  • Razer 非常适合使用 .NET 模型格式化页面,但在尝试绑定 AJAX/JavaScript 调用时几乎没有用处。要么使用带有“#!”的 hacky href 的锚标签或其他一些 html 元素、一个公共类并使用 JQuery 点击处理程序来传递 w/e 数据需要发送到控制器。

标签: c# jquery asp.net-mvc razor model-view-controller


【解决方案1】:

这样的事情应该可以帮助您入门。为您需要从中提取信息的项目添加一个类。然后,不要使用 actionlink,只需创建一个具有唯一类的普通 a 元素。让 JQuery 处理这些链接上的点击事件,并通过 AJAX 调用将同一行的其他 TD 项传递给控制器​​。

$(".button").click( function() {
	var tr = $(this).closest("tr");
  var ProductCodeScheme = tr.find(".ProductCodeScheme").html();
  var SerialNumber = tr.find(".SerialNumber").html();
  var Batch = tr.find(".Batch").html();
  var ExpirationDate = tr.find(".ExpirationDate").html();
  var ProductCode = tr.find(".ProductCode").html();
  
  $.ajax({
    url: "/Verify Pack/VerifyPack", 
    type: "POST",      
    data: ({
    	ProductCodeScheme: ProductCodeScheme,
      SerialNumber: SerialNumber,
      Batch: Batch,
      ExpirationDate: ExpirationDate,
      ProductCode: ProductCode
    }),     
    cache: false,
    success: function(data){                          
      //Do something here for a successful POST                   
    }           
  });    
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<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>
      <tr>
         <td>Timestamp 1</td>
         <td class="ProductCodeScheme">ProductCodeScheme 1</td>
         <td class="SerialNumber">SerialNumber 1</td>
         <td class="Batch">Batch 1</td>
         <td class="ExpirationDate">ExpirationDate 1</td>
         <td class="ProductCode">ProductCode 1</td>
         <td>HttpResponseCode 1</td>
         <td>ConfirmedParsed 1</td>
         <td>ConfirmedDate 1</td>
         <td class="text-secondary"><a href="#!" class="button">Item 1</a></td>
      </tr>
     <tr>
         <td>Timestamp 2</td>
         <td class="ProductCodeScheme">ProductCodeScheme 2</td>
         <td class="SerialNumber">SerialNumber 2</td>
         <td class="Batch">Batch 2</td>
         <td class="ExpirationDate">ExpirationDate2</td>
         <td class="ProductCode">ProductCode 2</td>
         <td>HttpResponseCode 2</td>
         <td>ConfirmedParsed 2</td>
         <td>ConfirmedDate 2</td>
         <td class="text-secondary"><a href="#!" class="button">Item 2</a></td>
      </tr>
   </tbody>
</table>

【讨论】:

    【解决方案2】:

    基本上@Html.ActionLink() helper 使用属性渲染锚标记(&lt;a&gt;)并默认通过刷新整个页面来使用 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 属性中提取查询字符串参数,并在带有type: 'POST' 设置的AJAX 调用中使用它们,或者使用$.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.ActionLink())调用 AJAX,具体取决于您的选择:

    @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()(或 Core MVC 中的 Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")区分它们。

    【讨论】:

    • 谢谢。但是,在使用提取字符串查询参数的 jQuery 解决方案后,我仍然被重定向到 /Home/VerifyPack。我已将错误屏幕截图添加到原始问题中。
    • 听起来你对click 事件绑定有问题。尝试将e.preventDefault() 移动到click 事件的最底部。
    猜你喜欢
    • 2020-10-10
    • 2021-06-20
    • 2020-05-01
    • 2019-01-08
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多