Id 在 Action 方法中变为 Null

Id coming Null in the Action Method

不知道为什么,我的 Action 方法显示 id 为 null。我在 url 中传递了 id 但它仍然是 null

控制器动作方法

public ActionResult SpecificEmpDetails(string empId)
{
    CustomerBAL customer = new CustomerBAL();
    Customer custs = customer.Employees.Single(emp => emp.EmpID.ToString() == empId);
    ViewBag.Customers = custs;
    return View("EmpDetails");
}

查看

   <ul>
            <li>
                Customer ID : @ViewBag.Customers.EmpID
            </li>
            <li>
                Customer Name : @ViewBag.Customers.EmpName
            </li>
            <li>
                Customer Age : @ViewBag.Customers.EmpAge
            </li>
            <li>
                Customer Gender : @ViewBag.Customers.EmpGender
            </li>
            <li>
                Customer Salary : @ViewBag.Customers.EmpSalary
            </li>
        </ul>

员工数据库上下文

public class CustomerBAL : DbContext
{
    public DbSet<Customer> Employees { get; set; }
}

员工模型Class

[Table("tblEmployee")]
public class Customer
{
    [Key]
    public int EmpID { get; set; }
    public string EmpName { get; set; }
    public string EmpGender { get; set; }
    public int EmpAge { get; set; }
    public int EmpSalary { get; set; }
}

路由配置

routes.MapRoute(
               name: "SpecificUser",
               url: "{controller}/{action}/{id}",
               defaults: new { controller = "Test", action = "SpecificEmpDetails", id = UrlParameter.Optional }
           );

URL

localhost:8983/Test/SpecificEmpDetails/1

Id 为 null,但是当我在调试期间将 ID(在手表 window 中)从 null 更改为任何可用 ID 时,它会显示所需的员工数据。我完全不明白为什么 id 没有从 url.

传递给控制器​​操作方法

Url 中的 Id 不会传递到 empId 因为在 MapRoute 中,动作后的数字将转到 Id 而不是 empId

像这样更改您的操作,一切都会正常进行。

public ActionResult SpecificEmpDetails(string Id)
{
    CustomerBAL customer = new CustomerBAL();
    Customer custs = customer.Employees.Single(emp => emp.EmpID.ToString() == Id);
    ViewBag.Customers = custs;
    return View("EmpDetails");
}

如果你不想改变你的方法,你必须使用这个 url 来修复它:

localhost:8983/Test/SpecificEmpDetails?empId=1

这里发生了两件不同的事情。

路由

首先,你的路由定义是:

routes.MapRoute(
           name: "SpecificUser",
           url: "{controller}/{action}/{id}",
           defaults: new { controller = "Test", action = "SpecificEmpDetails", id = UrlParameter.Optional }
       );

您指定传递的路由值 的名称是{id}。因此,任何匹配此路由的 URL 将被输入到 URL table 中,路由键 id 和在 URL 中传递的值。

例如,对于 URL /Test/SpecificEmpDetails/1,您的路线 table 如下所示:

| Key         | Value               |
|-------------|---------------------|
| controller  | Test                |
| action      | SpecificEmpDetails  |
| id          | 1                   |

它看起来像这样的原因是因为您正在传递 URL 中的值,并且它们正在通过您定义的占位符转换为路由值。

价值提供者

MVC 获取操作方法参数值(或者从技术上讲,模型的任何值)的方式是通过值提供程序

值提供者从多个位置查找键,例如查询字符串参数、表单值和路由值,以尝试将 键名称 与每个位置中的内容相匹配字典。如果action方法的参数名匹配,就会传值。如果没有匹配,该值将是数据类型的默认值。

您可以通过查看静态 ValueProviderFactories.Factories 属性 查看默认注册的值提供程序(以及它们的优先顺序)。您还可以删除 add/insert 自定义值提供程序工厂到此 属性.

因此,使用 custom value provider,如果您确实愿意,您 可以 将一个名称映射到另一个名称。在这种情况下,您可以使键 empId 的请求与路由值 id.

匹配

也就是说,我建议您执行以下操作之一。

选项 1:使用默认路由,并坚持使用名称 "Id"

您提供的路由将无法在与默认路由相同的 MVC 应用程序中使用。原因是它将匹配 any URL 具有 0、1、2 或 3 个段 ,就像默认路由 一样。如果将此长度的 URL 传递给应用程序,它将匹配注册的第一个路由并忽略另一个。有关完整说明,请参阅

因此,如果您只在应用程序中使用一个路由,并使用 id 作为您的路由键和操作方法参数,一切都会相应地进行,并且 更简单 而不是使用自定义路由。

IMO,将 id 参数设为此特定 URL 的可选参数可能没有多大意义。无论如何,您的操作方法中没有代码来处理空 id 值。但是请注意,如果您传递 URL /Test/SpecificEmpDetails,它仍然会匹配 Default 路由并匹配您的控制器操作(具有空值)。为避免这种情况,您可以插入一个 IgnoreRoute 来阻止 URL 在这种情况下进行匹配。

// Ignore the URL if it is passed with no id, so you get a 404 not found
routes.IgnoreRoute("Test/SpecificEmpDetails");

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

以及你的操作方法:

public ActionResult SpecificEmpDetails(string id)
{
    CustomerBAL customer = new CustomerBAL();
    Customer custs = customer.Employees.Single(emp => emp.EmpID.ToString() == id);
    ViewBag.Customers = custs;
    return View("EmpDetails");
}

方案二:使用自定义路由,参数名称改为"empId"

如果您想要自定义路由,您必须约束 路由,这样它就不会匹配传递的每个 值。在这种情况下,您只希望它匹配 /Test/SpecificEmpDetails/<SomeID>,因此最简单的选择就是使用文字段而不是占位符。

您还需要,否则将是无法访问的执行路径。

如上所述,它仍然会匹配 Default 路由并匹配您的控制器操作(具有 null 值,因为 id 不等于 empId ).因此,在这种情况下,您还应该插入一个 IgnoreRoute 来阻止 URL 匹配。

// Ignore the URL if it is passed with no empId, so you get a 404 not found
routes.IgnoreRoute("Test/SpecificEmpDetails");

routes.MapRoute(
    name: "SpecificUser",
    url: "Test/SpecificEmpDetails/{empId}",
    defaults: new { controller = "Test", action = "SpecificEmpDetails" }
);

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

然后您就可以使用您在问题中使用的方法了。

public ActionResult SpecificEmpDetails(string empId)
{
    CustomerBAL customer = new CustomerBAL();
    Customer custs = customer.Employees.Single(emp => emp.EmpID.ToString() == empId);
    ViewBag.Customers = custs;
    return View("EmpDetails");
}