ASP MVC 表单调用特定操作而不是重定向但更新原始页面

Posted

技术标签:

【中文标题】ASP MVC 表单调用特定操作而不是重定向但更新原始页面【英文标题】:ASP MVC form to call specific action and not redirect but update original page 【发布时间】:2012-06-01 10:15:27 【问题描述】:

我正在将 ASP.net MVC 3 用于一个项目,现在我对它有了更多的了解,但也试图了解它与我使用了很长时间的 WebForms 世界之间的差异。以前在 WebForms 中,您只需将字段放在那里,添加一个按钮并创建一个事件,然后使用回发处理您需要的任何内容。

例如,我有一个显示错误详细信息的简单视图。我想将有关此错误的一些信息推送到我们的问题跟踪器的 API。让我们只说错误的主题和内容。我会在 html 中做类似的事情:

<form action="@Url.Action("Send")" method="post">
    <input id="subject" name="subject" type="text" value="@Model.subject" />
    <br />
    <input id="content" name="content" type="text" value="@Model.content" />
    <br />
    <input type="submit" value="Send" />
</form>

我发现将输入 ID 命名为与控制器中的参数名称相匹配,然后我就可以传递这些参数。这与您在 Scott Guthrie 的旧帖子中看到的相似。

首先,我想在我的错误控制器中调用“发送”操作,而不是我的详细信息。这实际上确实调用了我的“发送”操作,但随后重定向到 localhost/Errors/Send,这是我不希望的。

我希望能够提交此表单,该表单调用和操作并使用远程 API 完成工作,然后在当前页面上更新一条消息,说明错误已被转移。

一旦问题被提交给错误跟踪器,我该如何在原始页面上显示一个 DIV,将内容传回给它(例如,指向问题跟踪器中问题的链接)?

更新:这是我在控制器中所做的:

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost/redmine/issues.json");
request.Credentials = new NetworkCredential("username", "password");
request.Method = "POST";
request.ContentType = "application/json";
request.Accept = "application/json";

using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))

    writer.Write("'issue':  " +
                      "'project_id': 'project', " +
                      "'subject': 'Test issue'" +
                      "");


WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
string json = "";

using (StreamReader reader = new StreamReader(stream))

    json = reader.ReadToEnd();

另外,我认为这是我正在做的事情(简化,在 Phillip 的帮助下)

@model webapp.Models.app_errors

<script type="text/javascript">
 function SendErrors()     

           alert(@Model); // here I get a 'webapp undefined error'
           alert(Model); // Model is undefined. If I reference @Model.App_name or another value anywhere, works fine in rest of view

        $.ajax(
            type: 'POST', //(probably)
            url: '../SendToRedmine',
            cache: false, //(probably)
            dataType: 'json', //(probably)
            data: @Model,
            success: function(result)
            
                alert("The error has been transferred");
                //you can also update your divs here with the `result` object, which contains whatever your method returns
            
            );
    
</script>

<input type="button" onclick='SendErrors()'/>

【问题讨论】:

【参考方案1】:

针对您的第一个问题,试试这个 Url.Action 的重载:

Url.Action("ActionName","ControllerName")

你的第二个问题:你会想通过 AJAX 来做。

基本上,第一次加载页面时,将您想要显示的任何内容返回到屏幕上。然后,有一个这种形式的ajax函数:

<script type="text/javascript">
    function SendErrorsOrWhatever()
    
        dummy = 'error: myError, someOtherProperty = property';  //this of course assumes that 'myError' and 'property' exist
        $.ajax(
        type: 'GET', //i changed this because it actually probably better suits the nature of your request
        url: '../Details/Send',
        cache: false, //(probably)
        dataType: 'json', //(probably)
        data: dummy,  //json object with any data you might want to use
        success: function(result)
        
            alert("The error has been transferred");
            //you can also update your divs here with the `result` object, which contains whatever your method returns
        
        );
    
</script>

需要注意的几点: 1) 网址会自动附加以包含来自data 的数据。 2)您的操作方法现在需要接受一个参数。有很多方法可以解决这个问题。我在下面的代码中添加了一个示例,说明您的操作方法可能是什么样的。

然后您的按钮的onclick 事件将调用该函数,如下所示:

<input type="button" onclick='SendErrorsOrWhatever()'/>

这里发生的情况是,当你的按钮被点击时,Ajax 将异步(默认)点击你的动作方法,你的动作方法将做任何它需要做的错误,然后当它完成时,@ 987654326@回调将被命中。

编辑:现在,您的操作可能如下所示:

[AcceptVerbs(HTTP.Get)]
public static Error GetErrors(Error error)

    //do all your processing stuff

现在,假设 JSon 对象 dummyError 类具有相同的字段。如果是这样,MVC 将对其进行自动数据绑定。您也可以对参数使用更通用的FormCollection。真的,你可以使用任何你想要的东西,但你会想要将任何你想要的东西包装在一个 JSon 对象中。

编辑——对于你的最后一个问题,这应该有效:

将以下扩展方法添加到您的应用中:

public static class JsonExtensions

    public static string ToJson(this Object obj)
    
        return new JavaScriptSerializer().Serialize(obj);
    

或者如果你愿意,你可以在你的模型类中添加一个 ToJson() 方法,然后:

var model = @Model.ToJson();

在 ajax 调用之前的 js 中。然后为您的data 参数使用model 变量。

【讨论】:

在这种情况下,我的发送操作实际上是在执行 POST 吗?例如,提出我的网络请求、处理身份验证等?因此,“虚拟”在哪里填充? 这可以进行一些小的修改(实际上是逗号),但唯一的问题是我如何“加载”假人。与之前一样,我使用的是表单和操作。 其实data是要发送到服务器的对象。所以dummy 是您发送 服务器的内容。在此示例中,您可能尝试“加载”的是resultresult 是从 ajax 调用的任何操作(url)返回的——请记住,在 MVC 中,形式为 www.x.com/Controller/Action 的 url 将重定向到名为 Controller 的控制器中的“Action”操作.所以假设 action 返回一个 bool 是否显示错误消息(你可能想要更复杂的东西,比如一个 JSon 对象,但这是为了简单起见),-- 你会做一些如下形式的事情: if(result) //显示消息 这是有道理的。我想我要问的是如何将数据放入“虚拟”中,以及在我的控制器中会发生什么?目前,此代码使用 HTTPWebRequest 调用我的控制器(实际上是在正确地执行发布)。我知道如何将结果传回,只是对如何将我想要发布到服务的内容从视图传递回控制器感到困惑。【参考方案2】:

在 MVC 中,“动作”本质上是一个“页面”。 (不完全是,但通过路由,这最终大部分是正确的)

也就是说,您的操作被分组并导航到使用 MVC 框架内的路由。

我认为您在这里要做的是进行 AJAX 调用,将您的错误消息发送到 Web 服务。

除此之外,您可以使用 jQuery 插入一个隐藏的 div,其中包含一个带有另一个操作页面的 IFrame。不过,我不会推荐它。

【讨论】:

我对这一切都很熟悉,并且实际上喜欢 MVC 中的操作。而且我认为这也不是最好的方法。【参考方案3】:

有两种可能。

    在您的错误/发送操作中,将用户重定向回 l​​ocalhost/错误/详细信息页面。这可以通过控制器上的Redirect() 方法来完成。这种方法的问题是它是一个阻塞调用。并且用户必须等到远程 api 被调用并响应。

    使用 cmets 中提到的 AJAX 方法。缺点是它有点复杂,你可能需要轮询服务来检索状态,除非它是一个火而忘记的呼叫,那么它就是金钱。

使用 AJAX 是更优雅的解决方案。

【讨论】:

我会用 AJAX 方式来做,它主要是快速调用或失败。这会类似于菲利普的答案吗?【参考方案4】:

使用 AJAX 将是解决此问题的方法之一。但是您可能想重新考虑页面的行为。如果这是您的提交问题页面,您是否希望在提交问题后留在此页面上。如果我继续提交问题,您是否只想看到最新问题的链接?您可能必须轮询服务器以获取已提交问题的链接,这使得它变得更加困难。

在不了解需求的情况下,想出任何解决方案并不容易,但一般来说,一旦从提交页面(类似于 ~/issue/id)提交,我会转到不同的问题页面。

此外,您可以使用Html.TextboxFor(m=&gt;m.subject) 或类似的语法,这样您就不必为每个属性手动匹配输入ID。

【讨论】:

实际上是使用其他系统 API 将此问题发送到另一个系统。我基本上想要一个小表格,让我在提交之前对任何内容进行编辑。它不是为了实际编辑当前问题,只是将其发送到其他地方(几乎就像联系表格)

以上是关于ASP MVC 表单调用特定操作而不是重定向但更新原始页面的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 3 - 重定向到另一个动作

使用 web.config 中的 httpRedirect 将 asp.net MVC URL 重定向到特定的控制器/操作/参数

ASP .NET MVC:如果不满足特定条件,则重定向到视图

在 ASP.net MVC 5 应用程序中单击按钮时使用 JavaScript/jQuery 将用户重定向到页面

Spring MVC Controller 使用 URL 参数重定向而不是响应

如何重定向到 ASP.NET MVC 中的上一个操作?