将 /action/1,2,3 绑定到 List

发布于 2024-10-20 13:08:05 字数 788 浏览 2 评论 0原文

在我的 API 中,我希望有像 GET /api/v1/widgets/1,2,3GET /api/v1/widgets/best-widget,major- 这样的路由widget,bob-the-widget

public class WidgetsController : MyApiController
{
    public ActionResult Show(IEnumerable<int> ids)
    {

    }

    public ActionResult Show(IEnumerable<string> names)
    {

    }
}

我已经设置了路线以让我执行操作,但我不知道如何将 1,2,3 转换为 new List(){1, 2, 3} 等等。当然,我可以只获取一个字符串并在我的操作中解析它,但我想避免走这条路。

我想到的一件事是在 OnActionExecuting 方法中放入一些内容,但后来我不确定到底要放入什么内容(显然,我可以将一些东西组合在一起,但我正在尝试写一些可重用的东西。)

我的主要问题是如何知道我是否需要做任何事情(有时上游的 ValueProviders 会弄清楚所有事情),以及如何处理确定要转换为的类型(例如,如何我知道在这种情况下我需要转到整数集合或字符串集合,然后我该怎么做?)

顺便说一句,我有实现一个 ValueProvider 的想法以及,但在类似的问题上迷失了。

In my API, I'd like to have routes like GET /api/v1/widgets/1,2,3 and GET /api/v1/widgets/best-widget,major-widget,bob-the-widget

public class WidgetsController : MyApiController
{
    public ActionResult Show(IEnumerable<int> ids)
    {

    }

    public ActionResult Show(IEnumerable<string> names)
    {

    }
}

I've got routes set up to get me to the action, but I can't figure out how to turn 1,2,3 into new List<int>(){1, 2, 3} and so on. Of course, I could just take a string and parse it in my action, but I'd like to avoid going that route.

One thing that came to mind was to put something in the OnActionExecuting method, but then I wasn't sure exactly what to put in there (I could hack something together, obviously, but I'm trying to write something reusable.)

The main questions I have are how to know whether I need to do anything at all (sometimes the ValueProviders upstream will have figured everything out), and how to handle figuring out the type to cast to (e.g., how do I know that in this case I need to go to a collection of ints, or a collection of strings, and then how do I do that?)

By the way, I had the idea of implementing a ValueProvider as well, but got lost on similar questions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扛刀软妹 2024-10-27 13:08:05

我不知道如何将 1,2,3 转换为 new List(){1, 2, 3} 等等。

为了避免污染需要接收此参数的每个控制器操作,我建议使用自定义模型绑定器:

public class IdsModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = base.BindModel(controllerContext, bindingContext);
        var ids = bindingContext.ValueProvider.GetValue("ids");
        if (ids != null)
        {
            return ids.AttemptedValue
                      .Split(',')
                      .Select(id => int.Parse(id))
                      .ToList();
        }
        return result;
    }
}

然后在 Application_Start 中注册模型绑定器:

ModelBinders.Binders.Add(typeof(IEnumerable<int>), new IdsModelBinder());

最后您的控制器操作可能如下所示(从我的情况来看)可以在您的问题中看到它已经看起来像这样了:-)):

public ActionResult Show(IEnumerable<int> ids)
{
    ...
}

并且自定义模型绑定器将负责将 ids 路由令牌解析为相应的 IEnumerable 价值。

您可以对 IEnumerable 执行相同的操作,只需删除相应模型绑定器中的 .Select 子句即可。

I can't figure out how to turn 1,2,3 into new List(){1, 2, 3} and so on.

To avoid polluting each controller action that needs to receive this parameter I would recommend a custom model binder:

public class IdsModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = base.BindModel(controllerContext, bindingContext);
        var ids = bindingContext.ValueProvider.GetValue("ids");
        if (ids != null)
        {
            return ids.AttemptedValue
                      .Split(',')
                      .Select(id => int.Parse(id))
                      .ToList();
        }
        return result;
    }
}

and then register the model binder in Application_Start:

ModelBinders.Binders.Add(typeof(IEnumerable<int>), new IdsModelBinder());

and finally your controller action might look like this (and from what I can see in your question it already does look like this :-)):

public ActionResult Show(IEnumerable<int> ids)
{
    ...
}

and the custom model binder will take care for parsing the ids route token to the corresponding IEnumerable<int> value.

You could do the same with the IEnumerable<string> where you would simply remove the .Select clause in the corresponding model binder.

给妤﹃绝世温柔 2024-10-27 13:08:05

如果您的 URL 是

/api/v1/widgets/Show?names=best-widget&names=major-widget&names=bob-the-widget

This 会自行绑定:)

在这种情况下无需覆盖 modelbinders。
查询字符串变量names将绑定到您的Show-method_

public ActionResult Show(IEnumerablenames)

希望这有帮助!

if your URL was

/api/v1/widgets/Show?names=best-widget&names=major-widget&names=bob-the-widget

This would bind neatly by itself :)

No need to override modelbinders in this case.
The querystring-variable names will bind to your Show-method_

public ActionResult Show(IEnumerable<string> names)

Hope this helps!

々眼睛长脚气 2024-10-27 13:08:05

我对 ASP.Net MVC 相对较新,因此我不确定是否有更简单的方法来执行此操作,但是我的方法是执行如下操作:

public class WidgetsController : MyApiController
{
    public ActionResult Show(string ids)
    {
        List<int> parsedIds = new List<int>();
        foreach (var id in ids.Split(','))
        {
            parsedIds.Add(int.Parse(id));
        }
        return Show(parsedIds);
    }

    private ActionResult Show(List<int> ids);
}

您可能还想添加一些更复杂的方法对于无法解析输入的 ID 的情况进行错误处理,但这就是我将使用的一般方法。

I'm relatively new to ASP.Net MVC and so I'm not sure if there is an easier way of doing this or not, however my approach would be to do something like the following:

public class WidgetsController : MyApiController
{
    public ActionResult Show(string ids)
    {
        List<int> parsedIds = new List<int>();
        foreach (var id in ids.Split(','))
        {
            parsedIds.Add(int.Parse(id));
        }
        return Show(parsedIds);
    }

    private ActionResult Show(List<int> ids);
}

You might also want to add some more sophisticated error handling for cases where the IDs entered can't be parsed, but thats the general approach I would use.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文