C# 将查询字符串从/转换为对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9817591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 10:44:00  来源:igfitidea点击:

Convert querystring from/to object

c#asp.net-mvc-3

提问by Marc

I have this (simplified) class:

我有这个(简化的)类:

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

And I have to transform instances of it to a querystring like this:

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

"BaseNo=5&Width=100"

Additionally I have to transform such a querystring back in an object of that class.

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

I know that this is pretty much what a modelbinder does, but I don't have the controller context in my situation (some deep buried class running in a thread).

我知道这几乎是模型绑定器的作用,但是在我的情况下我没有控制器上下文(一些在线程中运行的深埋类)。

So, is there a simple way to convert a object in a query string and back without having a controller context?

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

It would be great to use the modelbinding but I don't know how.

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

采纳答案by Ivo

You can use reflection, something like this:

您可以使用反射,如下所示:

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;
 }

You'll need to implement the Parse method, just using int.Parse, decimal.Parse, DateTime.Parse, etc.

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

回答by Kirk Broadhurst

You can set the properties of this object in its constructor by retrieving the relevant values from the querystring

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

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

and you can ensure that the object is converted to the correct querystring format by overriding the ToStringmethod.

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

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

You'll still need to construct and call ToStringin the appropriate places, but this should help.

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

回答by dotjoe

This should work so long as none of the properties match any other route parameters like controller, action, id, etc.

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

new RouteValueDictionary(Model)

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

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

Initializes a new instance of the RouteValueDictionary class and adds values that are based on properties from the specified object.

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

To parse back from the query string you can use the model class as an action parameter and let the ModelBinder do it's job.

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

回答by Anupam Singh

Use this Parse method with the ivowiblo's solution (accepted answer):

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

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

回答by Ofer Zelig

You can just use .NET's HttpUtility.ParseQueryString()method:

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

HttpUtility.ParseQueryString("a=b&c=d")produces a NameValueCollectionas such:

HttpUtility.ParseQueryString("a=b&c=d")产生NameValueCollection这样的:

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

回答by ACM

A solution with Newtonsoft Json serializer and linq:

使用 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);

回答by Steven Pfeifer

Building off of Ivo and Anupam Singh's great solutions above, here is the code that I used to turn this into a base class for POST requests (in the event that you may only have the raw query string like in a Web API setup). This code works for lists of objects, but could easily be modified to parse a single object.

基于上面 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;
        }
}

Then you can inherit from this class in wrapper classes for POST requests and parse to whichever objects you need. In this case, the code parses a list of objects passed as a query string to a list of wrapper class objects.

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

For example:

例如:

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;
        }
    }
}