Как я сериализирую объект в формат строки запроса?

Как я сериализирую объект в формат строки запроса? Я, может казаться, не нахожу ответ на Google.Спасибо.

Вот объект, который я сериализирую как пример.

public class EditListItemActionModel
{
    public int? Id { get; set; }
    public int State { get; set; }
    public string Prefix { get; set; }
    public string Index { get; set; }
    public int? ParentID { get; set; }
}
60
задан 27 July 2011 в 21:00

3 ответа

Простой подход, который поддерживает свойства списка:

public static class UriBuilderExtensions
{
    public static UriBuilder SetQuery<T>(this UriBuilder builder, T parameters)
    {
        var fragments = typeof(T).GetProperties()
            .Where(property => property.CanRead)
            .Select(property => new
            {
                property.Name,
                Value = property.GetMethod.Invoke(parameters, null)
            })
            .Select(pair => new
            {
                pair.Name,
                List = (!(pair.Value is string) && pair.Value is IEnumerable list ? list.Cast<object>() : new[] { pair.Value })
                    .Select(element => element?.ToString())
                    .Where(element => !string.IsNullOrEmpty(element))
            })
            .Where(pair => pair.List.Any())
            .SelectMany(pair => pair.List.Select(value => Uri.EscapeDataString(pair.Name) + '=' + Uri.EscapeDataString(value)));

        builder.Query = string.Join("&", fragments);
        return builder;
    }
}

А более быстрое решение, которое с такой скоростью, как обстоятельно объясняет код для сериализации каждого типа:

public static class UriBuilderExtensions
{
    public static UriBuilder SetQuery<TSource>(this UriBuilder builder, TSource parameters)
    {
        var fragments = Cache<TSource>.Properties
            .Select(property => new
            {
                property.Name,
                List = property.FetchValue(parameters)?.Where(item => !string.IsNullOrEmpty(item))
            })
            .Where(parameter => parameter.List?.Any() ?? false)
            .SelectMany(pair => pair.List.Select(item => Uri.EscapeDataString(pair.Name) + '=' + Uri.EscapeDataString(item)));

        builder.Query = string.Join("&", fragments);
        return builder;
    }

    /// <summary>
    /// Caches dynamically emitted code which converts a types getter property values to a list of strings.
    /// </summary>
    /// <typeparam name="TSource">The type of the object being serialized</typeparam>
    private static class Cache<TSource>
    {
        public static readonly IEnumerable<IProperty> Properties =
            typeof(TSource).GetProperties()
            .Where(propertyInfo => propertyInfo.CanRead)
            .Select(propertyInfo =>
            {
                var source = Expression.Parameter(typeof(TSource));
                var getter = Expression.Property(source, propertyInfo);
                var cast = Expression.Convert(getter, typeof(object));
                var expression = Expression.Lambda<Func<TSource, object>>(cast, source).Compile();
                return new Property
                {
                    Name = propertyInfo.Name,
                    FetchValue = typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.PropertyType != typeof(string) ?
                        CreateListFetcher(expression) :
                        CreateValueFetcher(expression)
                };
            })
            .OrderBy(propery => propery.Name)
            .ToArray();

        /// <summary>
        /// Creates a function which serializes a <see cref="IEnumerable"/> property value to a list of strings.
        /// </summary>
        /// <param name="get">A lambda function which retrieves the property value from a given source object.</param>
        private static Func<TSource, IEnumerable<string>> CreateListFetcher(Func<TSource, object> get)
           => obj => ((IEnumerable)get(obj))?.Cast<object>().Select(item => item?.ToString());

        /// <summary>
        /// Creates a function which serializes a <see cref="object"/> property value to a list of strings.
        /// </summary>
        /// <param name="get">A lambda function which retrieves the property value from a given source object.</param>
        private static Func<TSource, IEnumerable<string>> CreateValueFetcher(Func<TSource, object> get)
            => obj => new[] { get(obj)?.ToString() };

        public interface IProperty
        {
            string Name { get; }
            Func<TSource, IEnumerable<string>> FetchValue { get; }
        }

        private class Property : IProperty
        {
            public string Name { get; set; }
            public Func<TSource, IEnumerable<string>> FetchValue { get; set; }
        }
    }
}

пример использования любого решения:

var url = new UriBuilder("test.com").SetQuerySlow(new
{
    Days = new[] { WeekDay.Tuesday, WeekDay.Wednesday },
    Time = TimeSpan.FromHours(14.5),
    Link = "conferences.com/apple/stream/15",
    Pizzas = default(int?)
}).Uri;

Вывод:
http://test.com/Days=Tuesday&Days=Wednesday&Time=14:30:00&Link=conferences.com%2Fapple%2Fstream%2F15
Ни одно из решений обрабатывают экзотические типы, индексированные параметры или вложенные параметры.

, Когда ручная сериализация более проста, этот подход c#7/.net4.7 может помочь:

public static class QueryParameterExtensions
{
    public static UriBuilder SetQuery(this UriBuilder builder, params (string Name, object Obj)[] parameters)
    {
        var list = parameters
            .Select(parameter => new
            {
                parameter.Name,
                Values = SerializeToList(parameter.Obj).Where(value => !string.IsNullOrEmpty(value))
            })
            .Where(parameter => parameter.Values.Any())
            .SelectMany(parameter => parameter.Values.Select(item => Uri.EscapeDataString(parameter.Name) + '=' + Uri.EscapeDataString(item)));
        builder.Query = string.Join("&", list);
        return builder;
    }

    private static IEnumerable<string> SerializeToList(object obj)
    {
        switch (obj)
        {
            case string text:
                yield return text;
                break;
            case IEnumerable list:
                foreach (var item in list)
                {
                    yield return SerializeToValue(item);
                }
                break;
            default:
                yield return SerializeToValue(obj);
                break;
        }
    }

    private static string SerializeToValue(object obj)
    {
        switch (obj)
        {
            case bool flag:
                return flag ? "true" : null;
            case byte number:
                return number == default(byte) ? null : number.ToString();
            case short number:
                return number == default(short) ? null : number.ToString();
            case ushort number:
                return number == default(ushort) ? null : number.ToString();
            case int number:
                return number == default(int) ? null : number.ToString();
            case uint number:
                return number == default(uint) ? null : number.ToString();
            case long number:
                return number == default(long) ? null : number.ToString();
            case ulong number:
                return number == default(ulong) ? null : number.ToString();
            case float number:
                return number == default(float) ? null : number.ToString();
            case double number:
                return number == default(double) ? null : number.ToString();
            case DateTime date:
                return date == default(DateTime) ? null : date.ToString("s");
            case TimeSpan span:
                return span == default(TimeSpan) ? null : span.ToString();
            case Guid guid:
                return guid == default(Guid) ? null : guid.ToString();
            default:
                return obj?.ToString();
        }
    }
}

использование В качестве примера:

var uri = new UriBuilder("test.com")
    .SetQuery(("days", standup.Days), ("time", standup.Time), ("link", standup.Link), ("pizzas", standup.Pizzas))
    .Uri;

Вывод:
http://test.com/?days=Tuesday&days=Wednesday&time=14:30:00&link=conferences.com%2Fapple%2Fstream%2F15

0
ответ дан 1 November 2019 в 10:20

Возможно, этот Универсальный подход будет полезен:

    public static string ConvertToQueryString<T>(T entity) where T: class
    {
        var props = typeof(T).GetProperties();

        return $"?{string.Join('&', props.Where(r=> r.GetValue(entity) != null).Select(r => $"{HttpUtility.UrlEncode(r.Name)}={HttpUtility.UrlEncode(r.GetValue(entity).ToString())}"))}";
    }
0
ответ дан 1 November 2019 в 10:20

Используя Json.Net это было бы намного легче путем сериализации и затем десериализации к парам значения ключа.

Вот пример кода:

using Newtonsoft.Json;
using System.Web;

string ObjToQueryString(object obj)
{
     var step1 = JsonConvert.SerializeObject(obj);

     var step2 = JsonConvert.DeserializeObject<IDictionary<string, string>>(step1);

     var step3 = step2.Select(x => HttpUtility.UrlEncode(x.Key) + "=" + HttpUtility.UrlEncode(x.Value));

     return string.Join("&", step3);
}
0
ответ дан 1 November 2019 в 10:20

Другие вопросы по тегам:

Похожие вопросы: