Подтвердить что ты не робот

Преобразовать запрос с/на объект

У меня есть этот (упрощенный) класс:

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

И мне нужно преобразовать экземпляры его в querystring следующим образом:

"BaseNo=5&Width=100"

Кроме того, мне нужно преобразовать такой запрос в объект этого класса.

Я знаю, что это в значительной степени то, что делает modelbinder, но у меня нет контекста контроллера в моей ситуации (некоторый глубокий скрытый класс работает в потоке).

Итак, есть ли простой способ конвертировать объект в строку запроса и обратно без контекста контроллера?

Было бы здорово использовать привязку к модели, но я не знаю, как это сделать.

4b9b3361

Ответ 1

Вы можете использовать отражение, что-то вроде этого:

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 и т.д.

Ответ 2

Используйте этот метод Parse с решением ivowiblo (принятый ответ):

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

Ответ 3

Решение с сериализатором 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);

Ответ 4

Вы можете установить свойства этого объекта в своем конструкторе, извлекая соответствующие значения из строки запроса

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 в соответствующих местах, но это должно помочь.

Ответ 5

Это должно работать до тех пор, пока ни одно из свойств не будет соответствовать другим параметрам маршрута, таким как контроллер, действие, идентификатор и т.д.

new RouteValueDictionary(Model)

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

Инициализирует новый экземпляр класса RouteValueDictionary и добавляет значения, основанные на свойствах указанного объекта.

Для анализа из строки запроса вы можете использовать класс модели в качестве параметра действия и позволить ModelBinder выполнять эту работу.

Ответ 6

Вы можете просто использовать метод .NET HttpUtility.ParseQueryString():

HttpUtility.ParseQueryString("a=b&c=d") создает a NameValueCollection как таковой:

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

Ответ 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 data types and values
            string[] entriesRaw = raw.Split('&');

            // Set the first property name if it is not provided
            if (firstPropertyNameOfObjectToParseTo == null)
                firstPropertyNameOfObjectToParseTo = entriesRaw[0];

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