Asp。Net mvc 5 -如何在Html.ActionLink()中传递一个复杂的对象作为路由值,以便默认的模型绑定器可以映射它?

时间:2022-12-02 11:37:58

I have an object containing searching, sorting and paging parameters as well as an id of a record to be edited.

我有一个包含搜索、排序和分页参数的对象,以及要编辑的记录的id。

I'd like to pass this object into Html.ActionLink() as a route value object, so that the resulting query string will be correctly mapped by the default model binder into the Edit action's parameter, which is an EditViewModel.

我想把这个对象传递到Html.ActionLink()作为一个路由值对象,这样生成的查询字符串就会被默认的模型绑定器正确地映射到Edit action的参数中,这是一个EditViewModel。

The idea is that after the Edit action completes, it can redirect back to the Index and maintain the same paging/sorting position, in the same data set, and filtered by the same search string.

其思想是,在编辑操作完成后,它可以重定向回索引,并在相同的数据集中保持相同的分页/排序位置,并通过相同的搜索字符串进行过滤。

Edit View Model:

编辑视图模型:

public class EditViewModel
{
    public SearchSortPageViewModel SearchSortPageParams { get; set; }
    public int Id { get; set; }

    public EditViewModel() 
    {
        SearchSortPageParams = new SearchSortPageViewModel();
        Id = 0;
    }

    public EditViewModel(SearchSortPageViewModel searchSortPageParams, int id)
    {
        SearchSortPageParams = searchSortPageParams;
        Id = id;
    }
}

public class SearchSortPageViewModel
{
    public string SearchString { get; set; }
    public string SortCol { get; set; }
    public string SortOrder { get; set; }
    public int Page { get; set; }
    public int PageSize { get; set; }
}

Edit action:

编辑动作:

public ActionResult Edit(EditViewModel evm)
    {
        /* ... */
    }

When I do this in the view:

当我这样做的时候

@model MyApp.Areas.Books.ViewModels.Books.IndexViewModel
...
@{EditViewModel evm = new EditViewModel(Model.SearchSortPageParams, item.ID);}
@Html.ActionLink("Edit", "Edit", evm)

I get this:

我得到了这个:

http://localhost:63816/Books/Books/Edit/4?SearchSortPageParams=MyApp.Areas.Base.ViewModels.SearchSortPageViewModel

But I want this:

但是我希望这个:

http://localhost:63816/Books/Books/Edit/4?SearchSortPageParams.SearchString=abc&SearchSortPageParams.SortCol=name&SearchSortPageParams.SortOrder=asc&SearchSortPageParams.Page=1&SearchSortPageParams.PageSize=3

The only way I have been able to pass the object so far has been to manually prepare the query string, like this:

到目前为止,我能够通过对象的唯一方法是手工编写查询字符串,如下所示:

@{string theQueryString = "?SearchSortPageParams.SearchString=" + @evm.SearchSortPageParams.SearchString + "&SearchSortPageParams.SortCol=" + @evm.SearchSortPageParams.SortCol + "&SearchSortPageParams.SortOrder=" + @evm.SearchSortPageParams.SortOrder + "&SearchSortPageParams.Page=" + @evm.SearchSortPageParams.Page + "&SearchSortPageParams.PageSize=" + @evm.SearchSortPageParams.PageSize;}
<a href="@Url.Action("Edit", new { evm.Id })@(theQueryString)">Edit</a>

I thought of writing a custom model binder, but it seems silly given that the default model binder already handles nested objects if formatted as a query string in the way it expects.

我曾考虑过编写自定义模型绑定器,但考虑到默认的模型绑定器已经按照预期的方式将嵌套对象格式化为查询字符串,这似乎有些愚蠢。

I also thought of writing a custom object serializer which outputs a serial format which the default model binder expects, but haven't yet gone down that route.

我还考虑过编写一个自定义对象序列化器,它输出的串行格式是默认模型绑定器所期望的,但还没有采用这种方法。

Finally, I thought of flattening out the EditViewModel so there is nothing nested, just have all the properties listed out flatly. But, it's not ideal.

最后,我想要将EditViewModel扁平化,这样就不会嵌套了,只需将所有的属性全部列出即可。但是,这不是理想的。

So, what is the best way to go?

那么,最好的方法是什么呢?

1 个解决方案

#1


9  

As far as I know, you can't pass the complex object directly, but you can avoid having to build the query string yourself by passing a RouteValueDictionary:

据我所知,您不能直接传递复杂的对象,但是您可以通过传递RouteValueDictionary避免自己构建查询字符串:

@Html.ActionLink("Edit", "Edit", new RouteValueDictionary {
    {"SearchSortPageParams.SortOrder", evm.SearchSortPageParams.SortOrder },
    { /* etc... */ }
})

This should generate the query string as you need it.

这将根据需要生成查询字符串。

The only other alternative would be use reflection to iterate over the properties of the model and generate this dictionary that way but that would, in my opinion, be over-engineered.

另一种选择是使用反射来迭代模型的属性并以这种方式生成这个字典,但在我看来,这是过度设计的。

Of course, I would generally suggest in this situation that you just have your action method take separate parameters:

当然,在这种情况下,我通常会建议你采取行动方法,采取不同的参数:

public ActionResult Search(string searchString, SortOrder sortOrder, ...)

I'd generally consider this to be a more appropriate way to pass GET parameters to a method (of course, this could get unwieldy if you have a lot of parameters). Then you can just do the following, which is much tidier:

我通常认为这是将GET参数传递给方法的一种更合适的方式(当然,如果您有很多参数,这可能会变得很麻烦)。然后你可以做下面的事情,这样更整洁:

@Html.ActionLink("Edit", "Edit",
    new { sortOrder = evm.SearchSortPageParams.SortOrder, ... })

#1


9  

As far as I know, you can't pass the complex object directly, but you can avoid having to build the query string yourself by passing a RouteValueDictionary:

据我所知,您不能直接传递复杂的对象,但是您可以通过传递RouteValueDictionary避免自己构建查询字符串:

@Html.ActionLink("Edit", "Edit", new RouteValueDictionary {
    {"SearchSortPageParams.SortOrder", evm.SearchSortPageParams.SortOrder },
    { /* etc... */ }
})

This should generate the query string as you need it.

这将根据需要生成查询字符串。

The only other alternative would be use reflection to iterate over the properties of the model and generate this dictionary that way but that would, in my opinion, be over-engineered.

另一种选择是使用反射来迭代模型的属性并以这种方式生成这个字典,但在我看来,这是过度设计的。

Of course, I would generally suggest in this situation that you just have your action method take separate parameters:

当然,在这种情况下,我通常会建议你采取行动方法,采取不同的参数:

public ActionResult Search(string searchString, SortOrder sortOrder, ...)

I'd generally consider this to be a more appropriate way to pass GET parameters to a method (of course, this could get unwieldy if you have a lot of parameters). Then you can just do the following, which is much tidier:

我通常认为这是将GET参数传递给方法的一种更合适的方式(当然,如果您有很多参数,这可能会变得很麻烦)。然后你可以做下面的事情,这样更整洁:

@Html.ActionLink("Edit", "Edit",
    new { sortOrder = evm.SearchSortPageParams.SortOrder, ... })