Ответы пользователя по тегу .NET
  • Непонятное объяснение нового пула потоков в .NET - кто-нибудь может разъяснить?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Все просто.
    Ребята поработали со старым механизмом и выяснили, что в условиях 100500 задач в секунду слишком много времени уходит на синхронизацию доступа потоков к одной единственной очереди задач.
    Чтобы подобную проблему разрулить, решили в условиях перегрузок разделить глобальную очередь на несколько локальных - с тем, чтобы рабочий поток мог работать с этой локальной очередью без использования блокировки (соответственно, без простоя на ожидании этой блокировки).
    Вот и все. Как только локальная очередь заканчивается, - работа идет с чужими локальными очередями и с глобальной очередью.
    В общем, не парьтесь. Если у вас 10 задач в секунду, считайте ничего не поменялось.
    А если 100500, то времени на ожидание блокировок будет уходить меньше. И производительность пула в этом случае возрастет.
    Ответ написан
  • Стек технологий для разработки корпоративного приложения с desktop клиентом?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Клиент: WPF.
    Сервер: C# на HttpListener.
    Транспорт: tls > http > json

    По минимуму нужно два exe-шника + 2 dll:

    1) на клиенте:
    — Client.exe - модуль запуска клиентского приложения: проверяет обновления, загружает по необходимости другие файлы с сервера, передает управление в UserInterface.dll
    — Common.dll - содержит программный код, общий как для клиентской, та и для серверной части;
    — UserInterface.dll - содержит код, специфический для клиентской части.

    2) на сервере:
    — AppServer.exe - работает в качестве службы Windows, содержит код, специфический для серверной части;
    — Common.dll - содержит программный код, общий как для клиентской, та и для серверной части.

    Опробовано многократно.
    Ответ написан
    Комментировать
  • Многопоточность ON DEMAND, или однопоточная многопоточность?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Чтобы разгрести всю эту кашу в голове, предлагаю применить RTFM-технологию:

    Thread Pooling in C#:
    https://docs.microsoft.com/en-us/dotnet/csharp/pro...

    Thread Synchronization in C#:
    https://docs.microsoft.com/en-us/dotnet/csharp/pro...

    Asynchronous Programming (C#):
    https://docs.microsoft.com/en-us/dotnet/csharp/async
    Ответ написан
    1 комментарий
  • NancyFx как узнать время выполнения асинхронного запроса?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Как обычно — засекаем момент начала и окончания обработки запроса на стороне сервера, считаем разницу:

    var sw = new Stopwatch();
    sw.Start();
    await MySuperCoolJobAsync();
    sw.Stop();
    Trace.WriteLine($"{sw.ElapsedMilliseconds} мс");


    Измерять время выполнения запросов нужно именно на стороне сервера.
    А на стороне клиента измеряют нагрузку, т.е. число запросов в секунду, которое сервер может обработать.
    Ответ написан
    2 комментария
  • Как исправить ошибку End of Stream encountered before parsing was completed?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    При передаче данных по сети иногда бывают паузы.

    Ваш код ждет первой такой паузы:

    while (stream.DataAvailable)

    ...и, не дожидаясь остальных данных, завершает чтение.

    Читать надо не пока DataAvailable, а пока не придет нужное количество байт. Для этого длину сообщения нужно сообщить клиенту перед отправкой самого сообщения.
    Ответ написан
  • Какие есть инструменты для автоматического улучшения/рефакторинга кода в .NET приложениях?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Есть. Деньги.
    Платишь их специалисту, клац, и все готово.
    Ответ написан
    Комментировать
  • Как настроить свойство зависимости в WPF?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    WPF не использует сеттер свойства "FormulaBinding" и вызывает "SetValue()" напрямую.
    Отследить изменения можно с помощью PropertyChangedCallback. Пример здесь:
    https://msdn.microsoft.com/en-us/library/system.wi...
    Ответ написан
  • Как правильно дождаться выполнения всех потоков, созданных в цикле?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Написано все правильно.

    Чтобы понять, в чем проблема, давайте попробуем внутри метода "GenerateMonthSheet" вывести в лог две записи: начало работы, окончание работы (с указанием месяца).

    И посчитаем, сколько стартануло, сколько завершило работу.

    P.S. А как вы номер месяца в генератор передаете? И откуда берется переменная "sh"?
    Ответ написан
    1 комментарий
  • Entity Framework и реальная жизнь с высокой нагрузкой?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Пользуюсь аналогом EF.
    Выдерживает на практике нагрузочный тест в 400 rps.
    А у вас "высокие нагрузки" — это сколько?

    По поводу опасений — поддержу Богдана: изначально имеет смысл пользоваться удобным инструментом везде, где хочется. А тюнингом заниматься потом — точечно в тех местах, где (если вдруг) будет тормозить.
    Ответ написан
    1 комментарий
  • Как корректно получить handle консольного приложения?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Дополнение к ответу выше:

    RegisterDeviceNotification function
    Parameters
    hRecipient [in]
    A handle to the window or service that will receive device events for the devices specified in the NotificationFilter parameter. The same window handle can be used in multiple calls to RegisterDeviceNotification.

    Services can specify either a window handle or service status handle.

    [...]

    Remarks:
    Any application with a top-level window can receive basic notifications by processing the WM_DEVICECHANGE message. Applications can use the RegisterDeviceNotification function to register to receive device notifications.

    Services can use the RegisterDeviceNotification function to register to receive device notifications. If a service specifies a window handle in the hRecipient parameter, the notifications are sent to the window procedure. If hRecipient is a service status handle, SERVICE_CONTROL_DEVICEEVENT notifications are sent to the service control handler.
    Ответ написан
    Комментировать
  • Что вы думаете про UWP?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Мысль о том, что за UWP — будущее, была основана исключительно на том предположении, что рынок покорят мобильники и планшеты на винде.
    Увы, не покорили. И вряд ли это произойдет.
    В связи с этим UWP, именно как "универсальная" платформа, не актуальна.
    А для десктопа, соглашусь с коллегами выше, — никаких преимуществ относительно WPF нет.
    Ответ написан
    2 комментария
  • Что с кодировкой полученного контента?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Если вы уверены, что там UTF-8, то меняем это:
    var responseStr = await response.Content.ReadAsStringAsync();

    на это:
    var responseStr = Encoding.UTF8.GetString(await response.Content.ReadAsByteArrayAsync());


    А по-хорошему, следует посмотреть, какая кодировка указана в заголовке Content-Type, ее и использовать (Fiddler как раз это и делает).

    В любом случае, доверять задачу определения кодировок стандартным библиотекам считаю верхом наивности.
    Ответ написан
    5 комментариев
  • Какой есть эффективный и разумный способ парсинга JSON?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Пользуюсь простым самописным механизмом:

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    
    namespace MyNamespace
    {
        /// <summary>
        /// Выполняет преобразование текста формата JSON
        /// в граф объектов и обратно.
        /// </summary>
        public static class Json
        {
            /// <summary>
            /// Преобразует текст в формате JSON в граф объектов.
            /// </summary>
            /// <param name="text">Исходный текст в формате JSON</param>
            /// <returns>Граф объектов</returns>
            public static object Parse(string text)
            {
                return new JsonParser().Parse(text);
            }
    
            /// <summary>
            /// Преобразует граф объектов в текст формата JSON. Поддерживаются:
            /// - null
            /// - string
            /// - bool
            /// - int, double, decimal
            /// - List˂object˃
            /// - Dictionary˂string,object˃
            /// </summary>
            /// <param name="value">Граф объектов</param>
            /// <returns>Текст формата JSON</returns>
            public static string Stringify(object value)
            {
                return new JsonSerializer().ToString(value);
            }
        }
    
        class JsonSerializer
        {
            public string ToString(object obj)
            {
                return ObjectToString(obj);
            }
    
            private string ObjectToString(object o)
            {
                if (o == null)
                    return "null";
    
                if (o is bool b)
                    return b ? "true" : "false";
    
                if (o is int i)
                    return i.ToString(CultureInfo.InvariantCulture);
    
                if (o is double db)
                    return db.ToString(CultureInfo.InvariantCulture);
    
                if (o is decimal dc)
                    return dc.ToString(CultureInfo.InvariantCulture);
    
                if (o is List<object> l)
                    return ListToString(l);
    
                if (o is Dictionary<string, object> d)
                    return DictionaryToString(d);
    
                if (o is string s)
                    return StringToString(s);
    
                throw new ArgumentOutOfRangeException(nameof(o), o, "Unknown type.");
            }
    
            private static string StringToString(string s)
            {
                return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n") + "\"";
            }
    
            private string ListToString(List<object> a)
            {
                var sb = new StringBuilder();
                sb.Append("[");
                for (var i = 0; i < a.Count; ++i)
                {
                    if (i > 0)
                        sb.Append(", ");
    
                    var e = a[i];
                    sb.Append(ObjectToString(e));
                }
                sb.Append("]");
                return sb.ToString();
            }
    
            private string DictionaryToString(Dictionary<string, object> d)
            {
                var sb = new StringBuilder();
                sb.Append("{");
                var isFirst = true;
                foreach (var pair in d)
                {
                    if (isFirst)
                        isFirst = false;
                    else
                        sb.Append(", ");
    
                    sb.Append(StringToString(pair.Key) + ": ");
                    sb.Append(ObjectToString(pair.Value));
                }
                sb.Append("}");
                return sb.ToString();
            }
        }
    
        class JsonParser
        {
            private string Source;
    
            private int Offset;
    
            public object Parse(string source)
            {
                Source = source;
                Offset = 0;
                return ReadObject();
            }
    
            private object ReadObject()
            {
                SkipWhitespace();
                var c = Source[Offset];
                ++Offset;
                object item;
                switch (c)
                {
                    case '[':
                        item = ReadArray();
                        break;
                    case '{':
                        item = ReadDictionary();
                        break;
                    case '\"':
                    case '\'':
                        --Offset;
                        item = ReadString();
                        break;
                    case 'n':
                        item = ReadLiteral("ull", null);
                        break;
                    case 't':
                        item = ReadLiteral("rue", true);
                        break;
                    case 'f':
                        item = ReadLiteral("alse", false);
                        break;
                    default:
                        if (Char.IsDigit(c) || c == '-' || c == '.')
                        {
                            --Offset;
                            item = ReadNumber();
                        }
                        else
                            throw new FormatException();
                        break;
                }
    
                return item;
            }
    
            private Dictionary<string, object> ReadDictionary()
            {
                var result = new Dictionary<string, object>();
                while (true)
                {
                    SkipWhitespace();
                    var c = Source[Offset];
                    if (c == '}')
                    {
                        ++Offset;
                        break;
                    }
    
                    var key = ReadString();
                    SkipWhitespace();
                    c = Source[Offset];
                    if (c != ':')
                        throw new FormatException();
    
                    ++Offset;
                    var value = ReadObject();
                    result.Add(key, value);
    
                    SkipWhitespace();
                    c = Source[Offset];
                    if (c == ',')
                        ++Offset;
                    else if (c == '}')
                    {
                        ++Offset;
                        break;
                    }
                    else
                        throw new FormatException();
                }
    
                return result;
            }
    
            private void SkipWhitespace()
            {
                while (Offset < Source.Length && Char.IsWhiteSpace(Source[Offset]))
                {
                    ++Offset;
                }
            }
    
            private decimal ReadNumber()
            {
                var sb = new StringBuilder();
    
                while (Offset < Source.Length)
                {
                    var c = Source[Offset];
                    if (Char.IsDigit(c) || c == '-' || c == '.')
                        sb.Append(c);
                    else
                        break;
    
                    ++Offset;
                }
    
                return decimal.Parse(sb.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
            }
    
            private object ReadLiteral(string literal, object value)
            {
                if (Source.Length - Offset > literal.Length)
                {
                    if (Source.Substring(Offset, literal.Length) == literal)
                    {
                        Offset += literal.Length;
                        return value;
                    }
                }
    
                throw new FormatException();
            }
    
            private string ReadString()
            {
                SkipWhitespace();
    
                var result = new StringBuilder();
    
                var quote = '\0';
                var c = Source[Offset];
                if (c == '\"' || c == '\'')
                {
                    quote = c;
                }
                else if (!Char.IsLetter(c))
                    throw new FormatException();
                else
                    result.Append(c);
    
                while (true)
                {
                    ++Offset;
                    c = Source[Offset];
                    if (quote == '\0')
                    {
                        if (!Char.IsLetter(c) && !Char.IsDigit(c) && c != '_')
                            break;
                    }
                    else if (c == quote)
                    {
                        ++Offset;
                        break;
                    }
                    else if (c == '\\')
                    {
                        ++Offset;
                        c = Source[Offset];
                        if (c == 'u')
                        {
                            c = ReadUnicodeChar();
                        }
                    }
    
                    result.Append(c);
                }
    
                return result.ToString();
            }
    
            private char ReadUnicodeChar()
            {
                ++Offset; // u
                if (Source.Length - Offset < 4)
                    throw new FormatException();
    
                var digits = Source.Substring(Offset, 4);
                var result = ParseUnicodeChar(digits);
                Offset += 3; // 4 digits
                return result;
            }
    
            public static char ParseUnicodeChar(string digits)
            {
                if (!digits.ToCharArray().Any(Char.IsDigit))
                    throw new FormatException();
    
                var decValue = Convert.ToInt32(digits, 16);
                var s = Char.ConvertFromUtf32(decValue);
                if (s.Length != 1)
                    throw new FormatException();
    
                return s[0];
            }
    
            private List<object> ReadArray()
            {
                var result = new List<object>();
                while (true)
                {
                    SkipWhitespace();
    
                    var c = Source[Offset];
                    if (c == ']')
                    {
                        ++Offset;
                        break;
                    }
    
                    var obj = ReadObject();
                    result.Add(obj);
    
                    SkipWhitespace();
                    c = Source[Offset];
                    if (c == ',')
                    {
                        ++Offset;
                        continue;
                    }
    
                    if (c == ']')
                    {
                        ++Offset;
                        break;
                    }
                    
                    throw new FormatException();
                }
                
                return result;
            }
        }
    }
    Ответ написан
    1 комментарий
  • Почему не работает дуплексный WCF?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Брандмауэр мог заблокировать прослушивание:
    localhost:8733/Design_Time_Addresses/WCFDuplexServ...
    Ответ написан
    Комментировать
  • Что использовать для ретрансляции сообщений с сервера на клиент на .NET?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    TcpListener + async I/O
    Пример:
    https://ru.stackoverflow.com/a/337052/33301

    Пожалуй, ничего быстрее в .Net не найти.
    Ответ написан
    Комментировать
  • Как создать WPF окно в Dll?

    AlexanderYudakov
    @AlexanderYudakov
    C#, 1С, Android, TypeScript
    Все просто. Кнопка "добавить окно" отсутствует, но никаких запретов на окна в dll нет.

    На вскидку пара способов, как обойтись без кнопки:

    1. Создаете UserControl, переименовываете его в Window.

    2. Копируете пару файлов xaml и xaml.cs в папку проекта. В обозревателе решений жмем "Показать все файлы" - показываются те, которые не включены в проект, выбираем их, включаем в проект.
    Ответ написан
    Комментировать