【问题标题】:Convert querystring from/to object从/到对象转换查询字符串
【发布时间】:2012-04-06 17:42:02
【问题描述】:

我有这个(简化的)类:

public class StarBuildParams
{
    public int BaseNo { get; set; }
    public int Width { get; set; }
}

我必须将它的实例转换为这样的查询字符串:

"BaseNo=5&Width=100"

此外,我必须将这样的查询字符串转换回该类的对象中。

我知道这几乎是 modelbinder 所做的,但在我的情况下我没有控制器上下文(一些在线程中运行的深埋类)。

那么,有没有一种简单的方法可以在没有控制器上下文的情况下将查询字符串中的对象转换回来?

使用模型绑定会很棒,但我不知道如何。

【问题讨论】:

  • 我能想到的就是使用反射。
  • @ojlovecd 反射在这里有什么帮助?
  • 我相信这种情况是可以避免的。你能描述一下你的场景吗?你是如何在这个类中得到一个查询字符串的?
  • 嗨达林,我一直在等待你的回复,因为如果你说不可能,我相信 :) 我尝试存储一些有关操作图像的信息并需要将其作为查询字符串,因为我使用 @ 987654321@ 我必须在那里传递一个查询字符串。另外我想在其中存储一些自己的数据。我的图像生成器在一个线程中运行在几个图像上,每个图像都有自己的操作信息。
  • 哇,有 1000 次浏览,但没有点赞...

标签: c# asp.net-mvc-3


【解决方案1】:

您可以通过从查询字符串中检索相关值来在其构造函数中设置此对象的属性

public StarBuildParams()
{
    this.BaseNo = Int32.Parse(Request.QueryString["BaseNo"].ToString());
    this.Width = Int32.Parse(Request.QueryString["Width"].ToString());
}

您可以通过覆盖ToString 方法来确保将对象转换为正确的查询字符串格式。

public override string ToString()
{
    return String.Format("BaseNo={0}&Width={1}", this.BaseNo, this.Width);
}

您仍然需要在适当的位置构造和调用ToString,但这应该会有所帮助。

【讨论】:

    【解决方案2】:

    你可以使用反射,像这样:

    public T GetFromQueryString<T>() where T : new(){
        var obj = new T();
        var properties = typeof(T).GetProperties();
        foreach(var property in properties){
            var valueAsString = HttpContext.Current.Request.QueryString[property.PropertyName];
            var value = Parse( valueAsString, property.PropertyType);
    
            if(value == null)
                continue;
    
            property.SetValue(obj, value, null);
        }
        return obj;
     }
    

    您需要实现 Parse 方法,只需使用 int.Parse、decimal.Parse、DateTime.Parse 等。

    【讨论】:

      【解决方案3】:

      只要没有任何属性与任何其他路由参数(如控制器、操作、id 等)匹配,这应该可以工作。

      new RouteValueDictionary(Model)
      

      http://msdn.microsoft.com/en-us/library/cc680272.aspx

      初始化 RouteValueDictionary 类的新实例并添加 基于指定对象的属性的值。

      要从查询字符串中解析回来,您可以使用模型类作为操作参数并让 ModelBinder 完成它的工作。

      【讨论】:

      • 你能举个例子吗?
      • 我爱你的那行代码兄弟。它开箱即用,即使在 aspnetcore 2.2 webapi 代码上也是如此:)
      【解决方案4】:

      将此 Parse 方法与 ivowiblo 的解决方案一起使用(已接受的答案):

      public object Parse(string valueToConvert, Type dataType)
      {
          TypeConverter obj = TypeDescriptor.GetConverter(dataType);
          object value = obj.ConvertFromString(null, CultureInfo.InvariantCulture,  valueToConvert);
          return value;
      }
      

      【讨论】:

        【解决方案5】:

        您可以只使用 .NET 的 HttpUtility.ParseQueryString() 方法:

        HttpUtility.ParseQueryString("a=b&amp;c=d") 会生成一个NameValueCollection

        [0] Key = "a", Value = "b"
        [1] Key = "c", Value = "d"
        

        【讨论】:

          【解决方案6】:

          Newtonsoft Json 序列化器和 linq 的解决方案:

          string responseString = "BaseNo=5&Width=100";
          var dict = HttpUtility.ParseQueryString(responseString);
          string json = JsonConvert.SerializeObject(dict.Cast<string>().ToDictionary(k => k, v => dict[v]));
          StarBuildParams respObj = JsonConvert.DeserializeObject<StarBuildParams>(json);
          

          【讨论】:

          • 这在查询字符串包含数组时不起作用,例如P[0][A]=xxx& P[0][B]=yyyy&P[1][A]=aaaa&P[1][B]=bbbb
          • 这个答案拯救了我的整个职业生涯
          • 答案有效,我有一个包含多个项目的查询字符串。我可以设法将它们转换为 Poco 对象
          • 我爱你……你的回答就像一个魅力!
          【解决方案7】:

          以 Ivo 和 Anupam Singh 的上述出色解决方案为基础,这是我用来将其转换为 POST 请求的基类的代码(如果您可能只有 Web API 设置中的原始查询字符串) )。此代码适用于对象列表,但可以轻松修改为解析单个对象。

          public class PostOBjectBase
          {
                  /// <summary>
                  /// Returns a List of List<string> - one for each object that is going to be parsed.
                  /// </summary>
                  /// <param name="entryListString">Raw query string</param>
                  /// <param name="firstPropertyNameOfObjectToParseTo">The first property name of the object that is sent in the list (unless otherwise specified).  Used as a key to start a new object string list.  Ex: "id", etc.</param>
                  /// <returns></returns>
                  public List<List<string>> GetQueryObjectsAsStringLists(string entryListString, string firstPropertyNameOfObjectToParseTo = null)
                  {
                      // Decode the query string (if necessary)
                      string raw = System.Net.WebUtility.UrlDecode(entryListString);
          
                      // Split the raw query string into it's data types and values
                      string[] entriesRaw = raw.Split('&');
          
                      // Set the first property name if it is not provided
                      if (firstPropertyNameOfObjectToParseTo == null)
                          firstPropertyNameOfObjectToParseTo = entriesRaw[0].Split("=").First();
          
                      // Create a list from the raw query array (more easily manipulable) for me at least
                      List<string> rawList = new List<string>(entriesRaw);
          
                      // Initialize List of string lists to return - one list = one object
                      List<List<string>> entriesList = new List<List<string>>();
          
                      // Initialize List for current item to be added to in foreach loop
                      bool isFirstItem = false;
                      List<string> currentItem = new List<string>();
          
                      // Iterate through each item keying off of the firstPropertyName of the object we will ultimately parse to
                      foreach (string entry in rawList)
                      {
                          if (entry.Contains(firstPropertyNameOfObjectToParseTo + "="))
                          {
                              // The first item needs to be noted in the beginning and not added to the list since it is not complete
                              if (isFirstItem == false)
                              {
                                  isFirstItem = true;
                              }
                              // Finished getting the first object - we're on the next ones in the list
                              else
                              {
                                  entriesList.Add(currentItem);
                                  currentItem = new List<string>();
                              }
                          }
                          currentItem.Add(entry);
                      }
          
                      // Add the last current item since we could not in the foreach loop
                      entriesList.Add(currentItem);
          
                      return entriesList;
                  }
          
                  public T GetFromQueryString<T>(List<string> queryObject) where T : new()
                  {
                      var obj = new T();
                      var properties = typeof(T).GetProperties();
                      foreach (string entry in queryObject)
                      {
                          string[] entryData = entry.Split("=");
                          foreach (var property in properties)
                          {
                              if (entryData[0].Contains(property.Name))
                              {
                                  var value = Parse(entryData[1], property.PropertyType);
          
                                  if (value == null)
                                      continue;
          
                                  property.SetValue(obj, value, null);
                              }
                          }
                      }
                      return obj;
                  }
          
                  public object Parse(string valueToConvert, Type dataType)
                  {
                      if (valueToConvert == "undefined" || valueToConvert == "null")
                          valueToConvert = null;
                      TypeConverter obj = TypeDescriptor.GetConverter(dataType);
                      object value = obj.ConvertFromString(null, CultureInfo.InvariantCulture, valueToConvert);
                      return value;
                  }
          }
          

          然后您可以在 POST 请求的包装类中从此类继承并解析为您需要的任何对象。在这种情况下,代码会将作为查询字符串传递的对象列表解析为包装类对象列表。

          例如:

          public class SampleWrapperClass : PostOBjectBase
          {
              public string rawQueryString { get; set; }
              public List<ObjectToParseTo> entryList
              {
                  get
                  {
                      List<List<string>> entriesList = GetQueryObjectsAsStringLists(rawQueryString);
          
                      List<ObjectToParseTo> entriesFormatted = new List<ObjectToParseTo>();
          
                      foreach (List<string> currentObject in entriesList)
                      {
                          ObjectToParseToentryPost = GetFromQueryString<ObjectToParseTo>(currentObject);
                          entriesFormatted.Add(entryPost);
                      }
          
                      return entriesFormatted;
                  }
              }
          }
          

          【讨论】:

            【解决方案8】:

            序列化查询字符串并反序列化为您的类对象

             JObject json;
             Request.RequestUri.TryReadQueryAsJson(out json);
             string sjson = JsonConvert.SerializeObject(json);
             StarBuildParams query = JsonConvert.DeserializeObject<StarBuildParams>(sjson);
            

            【讨论】:

            • 这值得更多的支持。 TryReadQueryAsJsonSystem.Net.Http 中可用,并创建一个 JObject。不依赖于System.Web
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-10-01
            • 1970-01-01
            • 2014-09-17
            • 2014-03-17
            • 1970-01-01
            • 2013-02-16
            • 1970-01-01
            相关资源
            最近更新 更多