【问题标题】:What is the proper way to convert a route parameter to an integer?将路由参数转换为整数的正确方法是什么?
【发布时间】:2014-03-26 16:10:52
【问题描述】:

我正在尝试从 URL 中提取 ID。我的路线如下所示:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

Action 链接和生成的 URL 如下所示:

<li>@Html.ActionLink((string)link.Name, "Video", new { id = link.ID } )</li>
http://localhost:57762/Video/3 // <-- generated URL

然后我们进入控制器:

public ActionResult Video()
{
    int id = Convert.ToInt32(RouteData.Values["id"].ToString());
    var treatment = Treatment.Find(id);
    ViewBag.Title = treatment.Name;
    ViewBag.Treatment = treatment;
    return View();
}

这是奇怪的部分:

视图正确呈现所有内容。我可以整天访问 ViewBag.Treatment 并且一切都按预期工作,但是当我的浏览器完成加载视图时,Visual Studio 会抛出此异常:

在 mscorlib.dll 中发生了“System.FormatException”类型的异常,但未在用户代码中处理

附加信息:输入字符串的格式不正确。

它在抱怨这条线:

int id = Convert.ToInt32(RouteData.Values["id"].ToString());

我做错了什么?

【问题讨论】:

  • 嗯,为什么你的 ActionResult 视频没有int id 参数?类似public ActionResult Video(int id)
  • @RaphaëlAlthaus 没必要
  • @RaphaëlAlthaus 我不认为我完全理解你的评论。但看起来它可以解决我的问题。你能发布一个完整的答案吗?
  • @Selman22 什么不需要?
  • @anwyatt 定义了一个参数(我对 Raphael 说过),因为您已经在 routeconfig 中定义了它。我认为应该可以工作。

标签: c# asp.net-mvc model-binding


【解决方案1】:

在控制器中,您可以指定 id 是什么:

public ActionResult Index(int id)
{
  return View();
}

public ActionResult Index2(string id)
{
  return View();
}

模型绑定器将自动转换值(如果不能,则抛出黄屏)。

来自6 Tips for ASP.NET MVC Model Binding 的一些提示。 (我想在这里复制整个内容,但实际上只有提示是相关的)。

提示 #1:优先使用绑定而不是 Request.Form

如果你这样写你的动作..

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create()
{
    Recipe recipe = new Recipe();
    recipe.Name = Request.Form["Name"];

    // ...

    return View();
}

..那么你做错了。模型绑定器可以使您免于使用 Request 和 HttpContext 属性——这些属性使操作更难阅读和更难测试。更进一步的是使用 FormCollection 参数:

public ActionResult Create(FormCollection values)
{
    Recipe recipe = new Recipe();
    recipe.Name = values["Name"];      

    // ...

    return View();
}

使用 FormCollection,您不必深入研究 Request 对象,有时您需要这种低级别的控制。但是,如果您的所有数据都在 Request.Form、路由数据或 URL 查询字符串中,那么您可以让模型绑定发挥其魔力:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Recipe newRecipe)
{            
    // ...

    return View();
}

在此示例中,模型绑定器将创建您的 newRecipe 对象并使用它在请求中找到的数据填充它(通过将数据与配方的属性名称匹配)。这是纯粹的自动魔法。 customize绑定过程有很多方法,有“白名单”、“黑名单”、前缀和标记接口。为了更好地控制绑定发生的时间,您可以使用 UpdateModel 和 TryUpdateModel 方法。请注意无意绑定 - 请参阅 Justin Etheredge 的 Think Before You Bind

【讨论】:

  • +1:请注意,在 OP 的示例中,这也用作 Index(或“home”)操作。考虑评论如何处理/(没有id的root)url。
  • 听起来你想要回答 OP 没有问的问题。
  • 我相信 模型绑定器会自动转换值(如果不能,则抛出黄屏)。 是公平的警告。
【解决方案2】:

您可以让框架通过它的绑定功能为您执行此操作:

public ActionResult Video(int? id)

无需从路由数据中显式提取 id。

【讨论】:

    【解决方案3】:

    如果您真的希望该参数是可选的,则需要类似以下内容:

       public ActionResult Video(int? id) ...
    

    但是,当您实际拥有id 并相应地调整路线时,可能会更容易单独采取行动。

    【讨论】:

    • 重要的是要注意,在这个例子中,如果模型绑定器无法将字符串绑定到可为空的 int,那么/Home/Index/Test 仍然会抛出错误,但从积极的方面来说,如果 url 参数是empty/null 那么这是测试是否通过了 Id 的好方法(.HasValue = false 如果没有通过值)。
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 2020-07-06
    相关资源
    最近更新 更多