MVC将POST参数传递到字典中。

6
我有一个MVC应用程序,它在处理FormulaData对象后返回一个ResultObject。这是通过HTTP-Post调用的REST API。
[HttpPost]
[ActionName("GetResult")]
public ResultObjekt GetResult([FromBody]FormularData values)
{

}

问题:有没有一种方法可以将values中的所有属性读入Dictionary<string, string>IEnumerable<KeyValuePair<string, string>>中?

例如:

public class FormularData
{
    public string Item1 { get; set; }
    public string Item2 { get; set; }
}

应该将其转换为 Dictionary<string,string>()IEnumerable<KeyValuePair<string, string>>

使用值为 { {"Item1","Value1"}, {"Item2","Value2"}}

我的旧解决方案使用了 QuerystringHttpGet,而不是 HttpPost,自从我改变了之后,Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value) 不再起作用。


这是我当前的 - 不太优美的解决方案:

[HttpPost]
[ActionName("GetResult")]
public ResultObjekt GetResult([FromBody]FormularData values)
{
    List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
    if (!string.IsNullOrEmpty(values.Item1))
    {
        list.Add(new KeyValuePair<string, string>("Item1", values.Item1));
    }
    if (!string.IsNullOrEmpty(values.Item2))
    {
        list.Add(new KeyValuePair<string, string>("Item2", values.Item2));
    }
    IEnumerable<KeyValuePair<string, string>> result = list.AsEnumerable();
}

2
除非您需要将其绑定到FormularData类,否则您不能仅将“values”参数定义为“IDictionary<string, object>”吗? - Corporalis
3
@Toshi,“ResultObjekt GetResult([FromBody]Dictionary<string, object> values)”也应该可行。 - Nkosi
@Corporalis 我不能同时使用 FormularData 类和字典吗? - Toshi
@Toshi,请展示一下你打算如何传递模型的例子。 - Nkosi
如果你需要同时使用字典和FormulaData对象,则需要将其中一个作为参数进行指定,并在动作中进行映射。请问您是否真的需要两者,若是,请说明原因(考虑重构)。我假设您提供的控制器动作只是为了展示映射而进行简化。 - Corporalis
显示剩余5条评论
4个回答

10

正如评论中许多人已经提到的那样,理想情况下应该使用一个可以保存表单值的模型。在我看来,这也是最干净的方式,因为我发现它更加有条理。

如果需要同时访问两者,请首先尝试重构/重新组织代码,如果可能的话。在我看来,为什么要尝试访问原始表单数据,当它已经绑定到我们的模型上呢?毕竟,表单数据是模型数据的一个子集。

如果不能进行重构或重新组织,并且您需要同时访问两者,则有几种方法可以实现。

  1. 选项1:使用FormCollection

  2. [HttpPost]
    public ResultObjekt GetResult(FormCollection formCol, FormularData model)
    {
        //Note that here both FormCollection and FormularData are used.
        //To get values from FormCollection use something like below:
        var item1 = formCol.Get("Item1");
    }
    
  3. 选项2: 使用Request.Form

  4. [HttpPost]
    public ResultObjekt GetResult(FormularData model)
    {
        //To get values from Form use something like below:
        var formData = Request.Form;
        var item1 = formData.Get("Item1");
    }
    

希望这可以帮助。

更新: 正如Lali所指出的,无论您使用FormCollection还是Request.Form,您都可以将其转换为字典形式: formData.AllKeys.ToDictionary(k => k, v => formData[v])(未经测试),因为两者都是NameValueCollection类型。


4

虽然使用反射可能会影响性能,但您可以使用带有反射的linq将模型转换为字典。

[HttpPost]
[ActionName("GetResult")]
public ResultObjekt GetResult([FromBody]FormularData values)
{
    var result = values.GetType()
                     .GetProperties()
                     .ToDictionary(pi => pi.Name, pi => (string)pi.GetValue(values));
}

通过缓存从GetProperties返回的属性信息,可以提高性能。如果需要,上述linq也可以转换为扩展方法以便重用。


1
我认为你没有必要让生活变得更加困难。
如果你需要将你的类视为字典,只需实现一个隐式操作符,就像以下示例一样。

如果你只想在对象上进行迭代,可以实现IEnumerable。

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication5
{
    class Program
    {

        static void Main(string[] args)
        {
            FormularData data = new FormularData() { Item1 = "aa", Item2 = "bb" };
            //Dictionary<string, string> dictionary = data;
            foreach (var item in data)
                Console.WriteLine(item);

            Console.ReadLine();
        }
    }

    public class FormularData : IEnumerable<KeyValuePair<string,string>>
    {
        public string Item1 { get; set; }
        public string Item2 { get; set; }

        public static implicit operator Dictionary<string, string>(FormularData obj)
        {
            var list = new Dictionary<string, string>();
            if (!string.IsNullOrEmpty(obj.Item1))
                list.Add("Item1", obj.Item1);
            if (!string.IsNullOrEmpty(obj.Item2))
                list.Add("Item2", obj.Item2);
            return list;
        }

        public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
        {
            return ((Dictionary<string, string>)this).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}

1
扩展方法的威力可以在此处使用。
  1. Define an extension for FormularData class:

             public static class FormularDataExtensions
             {
                public static Dictionary<string, string> ConvertToDictionary(this FormularData formularData)
                {
                  var dictionary = new Dictionary<string, string>();
                  if (!string.IsNullOrEmpty(formularData.Item1))
                      dictionary.Add(nameof(formularData.Item1), formularData.Item1);
                  if (!string.IsNullOrEmpty(formularData.Item2))
                      dictionary.Add(nameof(formularData.Item2), formularData.Item2);
    
                 return dictionary;
                }
             }
    
  2. Call ConvertToDictionary() in GetResult() as:

    [HttpPost]
    [ActionName("GetResult")]
    public ResultObjekt GetResult([FromBody]FormularData values)
    {
        var dictionary = values.ConvertToDictionary();
    }
    

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