• Kaк защитить файл от слива в интернет?

    Ogoun
    @Ogoun
    Programmer
    Как вариант, для дополнений небольшого размера, при запуске проверяются доступные пользователю дополнения, сборки загружаются по защищенному соединению в оперативную память, и из нее подгружаются в приложение. Хранение на диске в этом случае не используется, а выдернуть сборку из памяти уже немного сложнее.

    В коде, грузим дополнение в байт массив, и загружаем через Assembly.Load(binary_asm)

    P.S. автоматом решается проблема с обновлениями
    Ответ написан
    Комментировать
  • Микросервисы на .net - оптимальный протокол "общения"?

    Ogoun
    @Ogoun
    Programmer
    Раньше использовать брокеры сообщений (RabbitMQ, ActiveMQ, NATS, ZeroMQ), в итоге пришел к общению посредством ServiceDiscovery.
    Т.е. в сети есть сервис который хранит таблицу адресов других сервисов и периодически ее раздает. Плюс проходит по таблице и пингует не пропал ли какой сервис из доступа. Остальные сервисы общаются друг с другом напрямую, получая адрес нужного сервиса из таблицы. При этом, если запущено несколько одинаковых сервисов, то передача данных им идет через round-roobin балансировку (конечно это для stateless сервисов, если есть состояние придется усложнить алгоритм общения).
    Транспорт может быть любой, использую REST или протокол поверх TCP как более быстрый вариант.
    Ответ написан
    Комментировать
  • Как запустить ASP.NET Core проект?

    Ogoun
    @Ogoun
    Programmer
    1. Прописываем в csproj
    <PropertyGroup>
    ...
        <RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
    ...
      </PropertyGroup>

    2. В терминале пишем команду
    dotnet publish -c Release -r win10-x64

    Получаем полностью готовое для запуска приложение под Windows.
    Ответ написан
    Комментировать
  • Как сделать solution explorer в С#?

    Ogoun
    @Ogoun
    Programmer
    Microsoft.Build
    Microsoft.Build.Engine.dll

    Для компиляции и работы с проектами советую использовать Microsoft.Build.Framework из nuget, он понимает синтаксис C# 7, у умеет работать с последними версиями .NET.

    Таким способом можно читать проекты из решения:
    public static void DbgReadSolution(string solution_file)
            {
                var wrapperContent = Microsoft.Build.BuildEngine.SolutionWrapperProject.
                    Generate(solution_file, toolsVersionOverride: null, projectBuildEventContext: null);
                byte[] rawWrapperContent = Encoding.Unicode.GetBytes(wrapperContent.ToCharArray());
                using (MemoryStream memStream = new MemoryStream(rawWrapperContent))
                using (XmlTextReader xmlReader = new XmlTextReader(memStream))
                {
                    var proj = ProjectCollection.GlobalProjectCollection.LoadProject(xmlReader);
                    int i = 0;
                    foreach (ProjectItem referencedProjectNode in GetOrderedProjectReferencesFromWrapper(proj))
                    {
                        Log.Info(String.Format("{0}{1}: {2}", Environment.NewLine, i++, referencedProjectNode.EvaluatedInclude));
                        string referencedProjectPath = Path.Combine(Path.GetDirectoryName(solution_file), referencedProjectNode.EvaluatedInclude);
                        var referencedProject = ProjectCollection.GlobalProjectCollection.LoadProject(referencedProjectPath);
                        Log.Info("\tReferenced Assemblies:");
                        foreach (ProjectItem referencedAssembly in GetReferencedAssemblies(referencedProject))
                        {
                            Log.Info("\t\t{0}", referencedAssembly.EvaluatedInclude);
                        }
                        Log.Info(String.Format("{0}\tSource Files:", Environment.NewLine));
                        foreach (ProjectItem includedSourceFile in GetSourceFiles(referencedProject))
                        {
                            Log.Info("\t\t{0}", includedSourceFile.EvaluatedInclude);
                        }
                    }
                    ProjectCollection.GlobalProjectCollection.UnloadAllProjects();
                }
            }
    Ответ написан
    Комментировать
  • WebDAV Ya.Disk и Flysystem: почему директории создаются а файлы не копируются?

    Ogoun
    @Ogoun
    Programmer
    Лучше не использовать ЯДиск, официальная документация не соответствует реальному API, разрабы меняют API без обратной совместимости и предупреждения. Общение с техподдержкой ни к чему не приводит.

    Тут можно посмотреть пример попытки общения с поддержкой по похожему вопросу.
    Ответ написан
  • Как изменить файл внутри zip архива?

    Ogoun
    @Ogoun
    Programmer
    1. Создать временный каталог
    2. Распаковать в него файлы
    3. Изменить файлы
    4. Упаковать каталог в архив
    5. Удалить временный каталог

    В пространстве имен System.IO.Compression.FileSystem.dll, есть удобный класс ZipFile, который умеет и упаковывать и распаковывать каталоги.

    ZipFile.CreateFromDirectory(tmp, zipPath);
    ZipFile.ExtractToDirectory(zipFile, targetFolder);
    Ответ написан
    Комментировать
  • Генерация дерева для каталогов, рекурсия?

    Ogoun
    @Ogoun
    Programmer
    var list = new List<string>();
    FillFolderList("C:\\", list, 0, 3, 3);
    
    
    public static void FillFolderList(string path, List<string> list, int current_level, int depth, int width)
    {
        list.Add(path);
        if (current_level >= depth) return;
        int current_width = 0;
        try
        {
            foreach (var subdir in Directory.GetDirectories(path))
            {
                FillFolderList(subdir, list, current_level + 1, depth, width);
                current_width++;
                if (current_width > width) break;
            }
        }
        catch (Exception)
        {
        }
    }
    Ответ написан
    3 комментария
  • Разумен ли self-hosting ASP.NET Web API приложения в службе Windows? Кто-нибудь использовал такое в проде?

    Ogoun
    @Ogoun
    Programmer
    Использую именно такой подход в проде, сервисы работаю как виндовс-службы, при старте сервис выбирает себе свободный порт и поднимает self-host webapi, по которому к нему может обращаться любой другой сервис. По скорости пока хватает, но планирую перейти на свой бинарный протокол сразу поверх TCP (по тестам до 20000 RPS получается добраться, на webapi до такого не дотянуть).
    Ответ написан
    7 комментариев
  • Изучение C#. Разработка по?

    Ogoun
    @Ogoun
    Programmer
    C# учить однозначно стоит, C++ если идти выше уровня middle тоже стоит, библиотеки на плюсах прекрасно оборачиваются шарпом и могут использоваться в местах где нужно скрыть код или ускорить выполнение.
    Также в довесок рекомендую учить питон, как бизнес-язык конечно он не подойдет, но прекрасен для выполнения разовых задач (преобразовать кучу файлов, умный калькулятор, поис по логам и т.п.)
    Ответ написан
    Комментировать
  • Как правильно переопредетиль Equals?

    Ogoun
    @Ogoun
    Programmer
    Использую такой вариант, после изучения вопроса сравнения объектов:

    public class Sample
    {
        public Guid Id;
    
        public bool Equals(Sample other)
        {
            if ((object)this == (object)other)
                return true;
            if (this == null)
                throw new NullReferenceException();
            if (other == null)
                return false;
            if (ReferenceEquals(this, other))
                return true;
            if (this.GetType() != other.GetType())
                return false;
            return Id == other.Id;
        }
    
        public override bool Equals(object obj)
        {
            return Equals(obj as Sample);
        }
    
        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }
    }
    Ответ написан
  • Как вынести логику работы в отдельные .dll? И как такое называется?

    Ogoun
    @Ogoun
    Programmer
    Специально для этих целей в стандартные библиотеки входи MEF
    Это намного проще чем писать свои host приложения на основе AppDomain.
    Ответ написан
    1 комментарий
  • C#. Как реализовать выполнение действий на сервере в real-time?

    Ogoun
    @Ogoun
    Programmer
    Уже выкладывал тут код для подобного вопроса, такое решение мне нравится низким потреблением ресурсов, на все про все один таймер. Работает стабильно. Состояние можно легко свопить на диск и восстанавливать, при рестарте сервера.
    Ответ написан
    Комментировать
  • Можно ли сделать универсальный репозиторий, который может работать и с EF и с ADO.NET?

    Ogoun
    @Ogoun
    Programmer
    Конечно, можно даже в принципе не знать что будет на физическом уровне. Хоть MongoDB, хоть бинарный файл.
    public interface IRepository<T>
    where T: IEntity
    {
        T Get(Guid Id);
        void Post(T entity);
        void Remove(Guid id);
    }
    
    public class EFRepository<T>: IRepository<T>
    where T: IEntity
    {
    /*Логика для EF*/
    }
    Ответ написан
    Комментировать
  • Простейший клиент - клиент. Всплывающее окно после передачи? На чём?

    Ogoun
    @Ogoun
    Programmer
    Для кастомного решения взял бы ZeroMQ, бесплатно, надежно, куча готовых сценариев, есть библиотеки под все основные языки. Оболочку можно сделать на WPF (C#).
    Статья
    Официальный сайт
    Примеры на различных языках
    Ответ написан
    Комментировать
  • Можно ли связать консольное c# приложение с веб-мордой?

    Ogoun
    @Ogoun
    Programmer
    В своих приложениях(консольные, win, сервисы) для доступа через http поднимаю self-host webAPI внутри этого же приложения. Соответственно там же можно отдавать простые веб-формы.
    Создание self-host WebAPI делается одной строкой: WebApp.Start(url: baseAddress);

    Соответственно, не нужен ни IIS, ни любой другой веб-вервер.
    Ответ написан
    Комментировать
  • Как читать и записывать xlsx стандартными средствами .NET?

    Ogoun
    @Ogoun
    Programmer
    Из всех библиотек которые перепробовал лучшим выбором, на мой взгляд, является NPOI, основные плюсы - не требует наличия офиса на машине, и умеет работать со старыми форматами (xls), в отличие от того же EPPlus.
    Для работы с Excel из nuget'а нужно установить сам NPOI и NPOI.ExcelExtend
    Ответ написан
    Комментировать
  • Работа статического метода при многопоточности?

    Ogoun
    @Ogoun
    Programmer
    В .NET разделяемыми ресурсами являются данные, но не методы. Т.е. все что находится в теле метода и сам метод, может обрабатываться параллельно в любом количестве потоков независимо друг от друга, а вот например поле статического класса уже будет видно сразу нескольким потокам и доступ к нему нужно делать потокобезопасным.
    По вашему вопросу, в общем случае нет разницы статический метод или нет, любой метод можно запустить на параллельное исполнение в разных потоках. Важно только следить как эти методы будут работать с общими ресурсами.
    Ответ написан
    Комментировать
  • Есть ли такой реализованный список на C#?

    Ogoun
    @Ogoun
    Programmer
    Для решения подобной задачи я использовал свое решение, где делал односвязный список объектов, обертывающих мой объект и добавляющих поле с временем удаления. Класс со списком объектов содержит один таймер, из Threading. При добавлении нового объекта он вставляется с сортировкой по дате, т.е. первый объект в списке всегда с самым коротким временем жизни, при добавлении/удалении перерасчитывается таймер. В итоге ресурсов потребляется мало, но сложность вставки/удаления O(N)

    Вот упрощенный рабочий пример:
    internal class TemporaryObject
    {
        private static long _counter = 0;
        public long Key { get; private set; }
        public TemporaryObject()
        {
            Key = Interlocked.Increment(ref _counter);
        }
        /// <summary>
        /// Событие при завершении ожидания
        /// </summary>
        public Action Callback;
        /// <summary>
        /// Срок истечения ожидания
        /// </summary>
        public DateTime ExpirationDate;
        /// <summary>
        /// Следующий объект с ближайшей датой окончания ожидания
        /// </summary>
        public TemporaryObject Next;
    }
    
    public class TemporaryObjectPool
    {
        private readonly object _locker = new object();
        /// <summary>
        /// Таймер. Один на всех
        /// </summary>
        private Timer _timer;
        /// <summary>
        /// Объект с ближайшей датой окончания ожидания
        /// </summary>
        private TemporaryObject _current = null;
        /// <summary>
        /// Переустановка таймера
        /// </summary>
        private void ResetTimer()
        {
            if (null != _current)
            {
                var diff = (_current.ExpirationDate - DateTime.Now).TotalMilliseconds;
                if (diff < 0) diff = 0;
                _timer.Change((int)diff, Timeout.Infinite);
            }
            else
            {
                _timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
        }
    
        public TemporaryObjectPool()
        {
            _timer = new Timer(state =>
            {
                Action action = null;
                lock (_locker)
                {
                    if (null != _current)
                    {
                        // Получаем событие для исполнения
                        action = _current.Callback;
                        // Находим следующий ожидающий объект
                        _current = _current.Next;
                        // Перезадание таймера
                        ResetTimer();
                    }
                }
                // Вызов события ожидавшего даты
                if (null != action)
                {
                    ThreadPool.QueueUserWorkItem(s => action());
                }
            }, null, Timeout.Infinite, Timeout.Infinite);
        }
    
        /// <summary>
        /// Добавление ожидающего объекта
        /// </summary>
        /// <param name="insert"></param>
        internal long Push(TemporaryObject insert)
        {
            lock (_locker)
            {
                // Если пул пуст, то добавляемое событие становится корневым
                if (null == _current)
                {
                    _current = insert;
                }
                else
                {
                    // Если пул не пуст
                    var cursor = _current;
                    TemporaryObject prev = null;
                    // Поиск места для вставки, сложность вставки O(n) в худшем случае
                    do
                    {
                        if (DateTime.Compare(cursor.ExpirationDate, insert.ExpirationDate) > 0)
                        {
                            insert.Next = cursor;
                            if (null == prev)
                            {
                                _current = insert;
                            }
                            else
                            {
                                prev.Next = insert;
                            }
                            break;
                        }
                        prev = cursor;
                        cursor = cursor.Next;
                        if (cursor == null)
                        {
                            prev.Next = insert;
                        }
                    } while (cursor != null);
                }
                ResetTimer();
            }
            return insert.Key;
        }
    
        public void Remove(long key)
        {
            lock (_locker)
            {
                if (_current == null) return;
                bool removed = false;
                if (_current.Key == key)
                {
                    _current = _current.Next;
                    removed = true;
                }
                else
                {
                    var prev = _current;
                    var next = _current.Next;
                    while (next != null)
                    {
                        if (next.Key == key)
                        {
                            prev.Next = next.Next;
                            removed = true;
                            break;
                        }
                        prev = next;
                        next = next.Next;
                    }
                }
                if (removed)
                {
                    ResetTimer();
                }
            }
        }
    }


    И использование
    var pool = new TemporaryObjectPool();
    pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#1 removed"), ExpirationDate = DateTime.Now.AddSeconds(5) });
    pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#2 removed"), ExpirationDate = DateTime.Now.AddSeconds(10) });
    pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#3 removed"), ExpirationDate = DateTime.Now.AddSeconds(15) });
    Ответ написан
    Комментировать