ASP.NET MVC - 如何从查询字符串中获取对象列表

6
我是一个有用的助手,可以为您翻译文本。

我会收到一系列参数,例如 "名称"、"ID"、"类型"。这些参数将在 URL 中出现多次,如下所示:

"Name=blah1,Id=231,Type=blah1;Name=blah2,Id=2221,Type=blah1;Name=blah3,Id=45411,Type=blah3;"

我想知道是否有一种方法可以将这些查询参数映射到一个对象列表。这样,我就可以创建一个对象:

MyTestObject {Name;Id;Type} ,并且在控制器中可以使用它。

Index(IList<MyTestObject> params)

参数将会填充来自查询字符串的数据。

类似于http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx的内容。


你尝试过在那个链接中提到的实现方法吗?我以前用过它,它满足了我的需求。 - Dirk
5个回答

5
我实际上遵循了 Haack 先生的文章中的建议。我创建了一个类,将所有参数作为公共属性。然后我有一个视图接受该类型对象的列表。如果查询参数名称遵循某种模式(以索引为前缀),那么我将自动获取填充的对象列表,而无需手动进行解析。对我来说,这是最简单的解决方案。
例子:
查询参数对象:
public class QueryParams
{
   public string Id,
   public string Name,
   public string Type
}

在控制器方法中:
public ActionResult Index(IList<QueryParams> queryData)

然后我会确保查询字符串按以下方式格式化(以索引为前缀):

http://localhost/myapp/?[0].id=123&[0].Name=blah&[0].Type=Person&[1].Id=345&[1].Name=example&[1].Type=Stuff

在我的控制器中,queryData列表参数将包含两个填充有正确数据的对象。

这其实非常简单,而且它能够完成工作! - Luis Palacios
我希望这种格式有更好的文档说明 - 它仍然适用于.NET5,但在经过数天挖掘后,这是我找到的第一个能够传递数组和复杂类型/对象的方法。谢谢!!! - carl-johan.blomqvist

4
您可以使用值提供程序,它将从查询字符串中填充值到单个对象中。如果您不打算创建视图模型,则应执行此操作。
通过以下方式将查询字符串转换为FormCollection:
var GetCollection = new FormCollection( Request.QueryString );

只需将其放入您的控制器中。 - Lucent Fox

3
你可以创建一个自定义模型绑定器,它使用Request.QueryString集合而不是常规的FormCollection
例如:
public class MyTestObjectModelBinder : DefaultModelBinder 
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    {
        var qs = controllerContext.HttpContext.Request.QueryString;                  
        return new MyTestObject
        {
           Name = qs["Name"],
           Id = qs["Id"],
           // etc, etc
        };
    }
}

然后根据需要设置你的 [HttpGet] 操作:

[HttpGet]
public ActionResult Index([ModelBinder(typeof(MyTestObjectModelBinder))]MyTestObject m) {

}

如果您喜欢,您也可以在全局范围内注册它,例如在 Application_Start() 中:
ModelBinders.Binders.Add(typeof(MyTestObject), new MyTestObjectModelBinder());

然后,您只需要在您的操作中使用该模型:
[HttpGet]
public ActionResult Index(MyTestObject m) {

}

话虽如此,如果你有这么多参数,那么必须问一下这些参数来自哪里?很可能是另一个页面上的表单。

在这种情况下,应该使用 [HttpPost] 操作,在表单集合中传递参数,然后常规的MVC模型绑定将为您处理上述代码。


1
+1 我也在考虑自定义模型绑定,但懒得自己写答案。 - CRice
@RPM1984 我可以这样做吗?这似乎是一个简单的解决方案。https://dev59.com/b1nUa4cB1Zd3GeqPZ10E#6748667 - dev.e.loper
@dev.e.loper - 如果这对你有用,当然没问题。不过,这可能会让维护变得困难,因为不清楚绑定是如何工作的,你必须维护两个地方(URL的生成和模型约定)。自定义模型绑定器则可以明确地进行绑定,并且只需保持一个位置即可维护绑定。不过,无论什么方法适合你就行。 - RPM1984

1

是的,ASP.NET MVC可以自动将集合绑定到操作参数,但您需要将参数作为表单值传递,此外,看起来您要在查询字符串中传递太多参数。看看这个链接http://weblogs.asp.net/nmarun/archive/2010/03/13/asp-net-mvc-2-model-binding-for-a-collection.aspx

基本上你需要做的是:

1)创建包含参数的类

public class MyParam 
{
 public int Id {get; set;}
 public string Name {get; set;}

 //do all the rest
}

2) 创建一个模型,然后将其传递给视图

public class MyViewModel
{
  IList<MyParam> MyParams {get; set;}
}

3) 在你的 [HttpGet] 操作中创建你的集合并将其传递给你的视图:

[HttpGet]
public virtual ActionResult Index()
{
   MyViewModel model = new MyViewModel();
   model.MyParams = CreateMyParamsCollection();

   return View(model);
}

4) 在视图中迭代您的集合

@model MyViewModel

@{int index = 0;}

@foreach (MyParam detail in Model.MyParams)
{
  @Html.TextBox("MyParams[" + index.ToString() + "].Id", detail.Id)
  @Html.TextBox("MyParams[" + index.ToString() + "].Name", detail.Name)

  index++;
} 

5) 然后在您的[HttpPost]操作中,您可以在集合中捕获参数

[HttpPost]
public virtual ActionResult Index(MyViewModel model)

或者

[HttpPost]
public virtual ActionResult Index(IList<MyParam> model)

P.S

此外,如果您想在控制器中获取所有表单参数,可以简单地这样做:
[HttpPost]    
public virtual ActionResult Index(FormCollection form)

https://dev59.com/b1nUa4cB1Zd3GeqPZ10E#6748667 - dev.e.loper

0

顺便提一下,我正在寻找一种枚举 QueryString 名称-值集合的方法,这是我想出来的:

        var qry =HttpContext.Request.QueryString;

        if (qry.HasKeys())
        {
            foreach (var key in qry)
            {
                if(key != null)
                    var str= String.Format("Key:{0}, value:{1} ", key, qry.Get(key.ToString()));
            }
        }

这段代码将返回查询字符串中所有名称及其值。

在 for each 语句中不能使用 str 变量声明。str 变量声明应该在 for each 语句之前。 - miguelbgouveia
并不重要。请查看以下评论https://dev59.com/zHI-5IYBdhLWcg3wYnOQ#Mp2cEYcBWogLw_1bmgu5 - Erik K.
问题在于,当代码在Visual Studio 2013中编译时,如果您在for each循环中声明变量,则会出现编译器错误。也许有一些配置可以防止这种情况发生,但默认情况下我们会得到编译器错误提示。 - miguelbgouveia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接