• Зачем использовать StringBuilder, если есть интерполяция?

    DarkRaven
    @DarkRaven
    разработка программного обеспечения
    Интерполяция представляет собой string.Format.
    StringBuilder дает API для эффективной работы со строковыми буферами.

    Подробно про StringBuilder:
    https://msdn.microsoft.com/en-us/library/system.te...
    https://professorweb.ru/my/csharp/charp_theory/lev...

    UPD 2023

    На текущий момент рекомендуется рассмотреть интерполяцию, в связи с улучшениями ее работы.
    Нам широко используются Span-ы и прочие штуки, что положительно сказывается на работе софта.
    Ответ написан
    Комментировать
  • Что за хайп вокруг питона?

    @fireSparrow
    Кроме TOBIE есть и другие рейтинги языков программирования.

    Рейтинг github - питон на втором месте.
    Рейтинг IEEE Spectrum - питон на первом месте.

    Питон очень прост и великолепно подходит для обучения основам программирования. Про Java, C, C++, которые по версии TOBIE опережают питон, такого сказать нельзя.
    Питон, скорее всего, ещё приподнимется в ближайшее время на волне интереса к машинному обучению, а вот Java, C и C++, скорее всего немного просядут.

    Ну и следует помнить, что рейтинг TOBIE основывается на количестве запросов о языке программирования в поисковиках. Поэтому в нём несколько завышена будет оценка для языков с большим количеством нюансов, и занижена для простых и понятных языков. Потому что когда технология и так понятна, про неё не будут много гуглить.
    Ответ написан
    Комментировать
  • Как можно обрезать?

    @4iloveg
    Full-Stack HTML Developer
    Ответ написан
    Комментировать
  • Образцовая реализация приложения на .NET Core?

    pprometey
    @pprometey Автор вопроса
    Software & Devops engineer TS/JS/C#/Angular2+/K8s
    Ответ написан
    Комментировать
  • C#: Как правильно получить доступ к конфигурациям в доменной модели?

    lam0x86
    @lam0x86
    Лучше не держать ничего лишнего в доменных сущностях. На мой взгляд, следует сделать IIssueService, в который перенести методы AcceptToWork, Close и т.д., которые будут принимать на вход ту Issue, над которой выполняется действие.
    И тогда можно конфигурить этот IIssueService различными менеджерами типа IConfigurationManager и IDateTimeProvider.
    Ответ написан
    Комментировать
  • Какие есть готовые C# библиотеки для работы с геообластями, ну или хотя бы с геометрией?

    @apro
    > Допустим я хочу переместить точку по азимуту на 100 метров

    Это же называется прямая (или обратная все время их путаю) геодезическая задача,

    Первая ссылка по поиску (c# direct geodesy problem):

    www.gavaghan.org/blog/free-source-code/geodesy-lib...

    >Очень долго искал, но не нашел ничего готового по трансформации зон, их перемещению, созданию буфера.

    Я бы взял postgis и использовал возможности c# по работе с sql
    Ответ написан
    3 комментария
  • Как лучше реализовать авторизацию в Web API?

    impwx
    @impwx
    Разработчик
    Да, это хорошая статья. Так оно обычно и делается - bearer token и атрибуты Authorize.

    Кроме обычных токенов есть еще дополнительный тип - refresh token. Они используются в том случае, если срок жизни первого токена истекает и нужно его обновить. Использовать их необязательно - зависит от кейса. Но на всякий почитайте:

    https://leastprivilege.com/2013/11/15/adding-refre...
    Ответ написан
    Комментировать
  • Насколько пригоден ASP.NET Core для стартового проекта?

    @MherArsh
    Привет!
    Я уже года полтора сижу с .NET на линуксе )) с начала был MONO с HyperFastGCI но когда вышел .Net Core наступило счастье. Стабильность и производительность норм, единственное что сейчас неудобно это то что надо билдить проект для каждой платформы, но это очень просто (во второй версии которая привю этот вопрос решили, теперь одна сборака на все) , проект запускается как самостоятельный сервис которой хостируется по Nginx, других вариантов не советую использовать, Nginx крутая штука! Единственное что сейчас отсутствует в .Net Core это oauth2, и во второй версии ее нет, есть библиотека под виндоу но о кроссплатформенности в этом случаи можно забыть. Я сам в читаном виде .Net Core не использую, до нее были разные интерфейсы для контролеров АПИ и сайта, сейчас все объединили, но много подводных камней, на рынке есть очень хорошие решения, я сам использую ServiceStack, есть еще Nancy, настоятельно рекомендую посмотреть на первый вариант, достаточно зрелый продукт который с коробки заводится под .net и имеет много готовых решений.
    Ответ написан
    Комментировать
  • Имеет ли юридическую силу запрет на парсинг сайта?

    @nirvimel
    Любые дополнительные юридические ограничения (сверх того, что требует государственное законодательство) можно навязать пользователю лишь одним способом - путем ДОБРОВОЛЬНОГО (с обеих сторон) заключения договора. Это обычно реализуется в виде пользовательского соглашения при регистрации на сайте. При этом одна сторона (сайт) обязуется предоставить какие-то услуги (например, доступ к некоторой информации), в то время как другая сторона (пользователь) добровольно принимает на себя какие-то ограничения (например, не пользоваться никакими автоматизированными средствами для извлечения, предоставляемой ему, информации). Это соглашения вступает в юридическую силу с момента нажатия на кнопку "Принимаю условия" (см. акцепт).
    Поскольку с анонимом в принципе невозможно заключить никакой договор (очевидно), то на, не прошедшего регистрацию пользователя, невозможно возложить никакие ограничения (сверх существующих в законе).

    Но все вышеописанное касается только СПОСОБА, которым пользователь взаимодействует с сайтом (автоматизированный/ручной/ножной/и.т.д.). Что касается самого контента, который пользователь потребляет, то на него распространяется все нормы авторского права (независимо от способа, которым он получен). Поскольку авторское право (как государственный закон и международное соглашение) распространяется на всех без исключения (в том числе и на анонимов), то не требуется заключать с пользователем никакого договора (и заставлять проходить регистрацию). Достаточно упомянуть (желательно на видном местом) запрет на использование данного контента в любых целях, кроме личного ознакомления. Это допустимо на основании того, что владелец исключительных прав на контент может определять любые ограничения на его использование. Что это дает: контент, собранный автоматизированными средствами, в дальнейшем не может быть использован никак без нарушения закона о защите авторских прав (это серьезнее, чем нарушение пользовательского соглашения). Это полный юридический тупик для того, кто захочет заняться парсингом (пусть даже само по себе это будет законно).
    Ответ написан
    2 комментария
  • Как начинать работу над проектом на фрилансе?

    RuJet
    @RuJet
    1. Обговариваешь ТЗ. Получаешь логины, явка, пароли.
    2. Обговариваешь срок, порядок и канал оплаты. Это тоже важно.
    3. Поднимаешь копию проекта у себя на хостинге/сервере и т.д. Не рекомендую пользоваться всяческими денверами. Например поведение php под liniux может отличаться от его поведения под windows.
    4. Кодишь, кодишь, кодишь.
    5. Показываешь заказчику на своем сервере.
    6. Получаешь оплату.
    7. Переносишь изменения к заказчику. Тут пригодится вышеупомянутый GIT.
    Рекомендации:
    На рабочем месте лучше держать linux. Во-первых как выше написал родная среда для web-приложений, во-вторых проще будет админить на vps и хостингах. А админить или хотя бы диагностировать проблему приходится часто. Особенно на мелких проектах.
    Использовать VCS, например GIT.
    Держать несколько каналов для оплаты. Например банковская карта, Яндекс.деньги, Qiwi и Webmoney.
    Сразу проработать схемы перевода прибыли в доступные для траты денежные средства.
    Не лениться и не бояться.
    Все начинали с мелких проектов, всех хоть раз кидали.
    Во фрилансе учатся на ошибках. Редко получается учиться по готовым руководствам и боже упаси всяким тренингам и видеокурсам.
    Ответ написан
    Комментировать
  • Чем отличается паттерн MVC от N layer архитектуры?

    denis_bardak
    @denis_bardak
    Web Developer
    Ответ написан
    Комментировать
  • Что такое enterprise разработка на самом деле?

    @miksir
    IT
    Enterprise разработка - это разработка, направленная на решение проблем бизнеса. В отличии от разработки для решения проблем конечных пользователей.

    На самом деле нет каких-то зафиксированных принципиальных характеристик, которые присущи только EA. По-этому, в разговорной речи понятие "энтерпрайз" может значить весьма разные вещи. С одной стороны энтерпрайз - не про увлечение модой с переписыванием всего, как только появится новый тренд. Ибо это _дорого_, так как цена ошибки дорога. С другой стороны - совсем не обязательно, что это 20-летние технологии. Конкретный бизнес сам для себя выбирает модели развития и обновления стека технологий. С одной стороны - это сложность ПО, бизнес-логики. С другой - сложность понятие весьма относительное.

    Но если все же пытаться выделить какие-то характерные черты, я бы назвал несколько:
    * устойчивость к трендам (использование их, когда они пройдут стадию моды и перейдут к стадии заинтересованности крупными игроками, ибо никому не нужны технологии, которые через год умрут и их поддержка будет дорожать каждый день).
    * сложная и непостоянная бизнес-логика, давление на нее из множества источников
    * результат сложной переменчивой бизнес-логики в совокупности с длительным использованием продукта приводит к целям снижения стоимости поддержки за счет стоимости первоначальной разработки, производительности и потребляемых ресурсов. ООП, SOLID, Unit Test/TDD, DDD - все эти популярные буквы - последствия "энтерпрайза", когда мы готовы серьезно подходить к написанию кода для облегчения его последующего изменения.
    * слабо заметный вклад конкретного программиста, проистекает из сложности ПО

    Требования к программисту... ну я бы сказал, усидчивость, вдумчивость, исполнительность... хм, а что, в каких-то других областях другие требования к программистам? Хотя, конечно, в противоположность, можно назвать способ разработки "быстро-быстро и в продакшн". Но, к слову, такие ситуации могут и в энтерпрайзе возникнуть.

    По-этому, стоит рассматривать не энтерпрайз/не энтерпрайз, а конкретные компании с конкретными требованиями и циклами разработки.
    Ответ написан
    1 комментарий
  • Сложный проект ASP.NET: выбор ORM?

    @Oblomingo
    Советую вам задуматься не только об ORM, но и об архитектуре вашего приложения.
    ORM позволяет очень быстро реализовать слой ответственный за трансформацию моделей базы данных в обьекты бизнес модели. Фактически, он реализует кучу таких классических паттернов как Data Mapper, Identity Map, Lazy Load, Repository, Unit of Work и еще кучу всего. Все это вы получаете из коробки + такие приятные вещи для контроля версии базы данных как CodeFirst + migrations. Да, в отдельных случаях вы расплачиваетесь скорость чтения/записи.
    Тут вам должна помочь правильная архитектура вашего приложения. Вы можете проектировать в соответсвии с принципами Domain-Driven-Design. В этом случае (в отличие от монолитного решения) приложения разделено на части. Каждая часть может иметь свою инфраструктуру, которая умеет записывать/читать данные из базы данных (repository pattern) и использовать какой то отдельный фреймворк. Части, которым не актуальна быстрая скорость, может легко использовать удобыный EF. Если в какой то части вы видите проблемы с быстродействием (bottleneck), вы можете изменить repository - выкинуть из нее EF и использовать Dapper. При правильной архитектуре, такая замена не затронет другие части системы и ваш рефакторинг пройдет безболезнено.

    Кроме того для EF есть расширения, которые реализуют Bulk функции:
    https://github.com/loresoft/EntityFramework.Extended
    entityframework-extensions.net
    https://efbulkinsert.codeplex.com/
    Ответ написан
    1 комментарий
  • Как запретить доступ к файлу в корне веб-приложения на IIS8?

    @WhiteNinja Автор вопроса
    Решил проблему следующим образом:

    <security>
     <system.webServer>
          <requestFiltering>
            <hiddenSegments>
              <add segment="config.json"/>
            </hiddenSegments>
          </requestFiltering>
        </security>
      </system.webServer>
    Ответ написан
    Комментировать
  • Какова правильная последовательность вызова методов Web Api?

    AlekseyNemiro
    @AlekseyNemiro
    full-stack developer
    Маркер доступа (access token) вдается один раз. На стороне клиента сохраняется в sessiongStorage либо в cookies. Используется при каждом запросе к API. Как правило, передавать маркер доступа лучше через заголовки. При использовании HTTPS заголовки будут зашифрованы.

    Для повышения безопасности, сервер может выдавать маркер доступа привязанный к конкретному IP (можно еще усложнить, например проверять браузер, тип системы и т.п.). Если адрес клиента не совпадает с адресом в базе, то аннулировать маркер доступа и предлагать клиенту получить новый маркер доступа.

    Срок действия маркер доступа может должен быть ограничен. Срок действия зависит от условий использования и необходимой степени безопасности. Например, если маркер привязан к IP, то срок действия вполне может быть продолжительным.

    На стороне сервера, для проверки доступа можно сделать отдельный фильтр, примерно как показано в коде ниже:

    class ApiAccess : AuthorizeAttribute
    {
    
      public override void OnAuthorization(HttpActionContext actionContext)
      {
        if (actionContext == null)
        {
          throw new ArgumentNullException("actionContext");
        }
    
        if (!this.IsAuthorized(actionContext))
        {
          return;
        }
      }
    
      protected override bool IsAuthorized(HttpActionContext actionContext)
      {
        bool isAuthroized = base.IsAuthorized(actionContext);
    
        // логика проверки доступа
    
        IEnumerable<string> authItems;
        if (actionContext.Request.Headers.TryGetValues("Authorization", out authItems))
        {
          var auth = authItems.First().Split(' ');
          var token = service.GetToken(auth.Last());
          // ...
        }
    
        return isAuthroized;
      }
    }

    Фильтр добавляется к контроллерам WebAPI, где необходима проверка доступа:

    [ApiAccess]
    public class FileServerController : ApiController
    {
    
       // ...
    
    }

    Со стороны клиента, проще сделать вспомогательный метод, который будет отправлять запросы в API с использованием маркера доступа, а также проверять необходимость получения нового маркера доступа (если сервер вернет ошибку). Примерно, как показано в следующем коде:

    let url = '/методAPI';
    let data = {}; // параметры запроса
    let headers = {
      'Authorization': 'ANYNAMEHERE ' + sessionStorage.getItem('token')
    };
    
    $.ajax({
      cache: false,
      processData: false,
      type: 'POST',
      url: url,
      contentType: 'application/json',
      dataType: 'json',
      data: JSON.stringify(data),
      headers: headers,
      success: (result) => {
        // успех
      },
      error: (x, textStatus, errorThrown) => {
         // ошибка
    
         // на сервер можно сделать исключение для плохих маркеров доступа
         // и проверить, если responseText содержит данный тип исключения,
         // то требовать у пользователя повторную авторизацию
        if (x.responseText) {
           let exception = JSON.parse(x.responseText);
           // AccessDeniedException - тип исключения в WebAPI, 
           // (скорее всего полное имя типа придется указывать)
           if (exception.ExceptionType == 'AccessDeniedException') { 
              // ...
           }
        }
      }
    });

    Что касается получения пользователем маркера доступа, то это можно сделать любым удобным способом. Например, показывать модальное окно для ввода логина и пароля, или перенаправлять на отдельную страницу.

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

    Если API используется в браузере, как есть, то маркер доступа можно передавать в параметрах запроса. Однако это небезопасно, т.к. данные будут в открытом виде.
    Ответ написан
    6 комментариев
  • Можно ли выполнять lock на list?

    impwx
    @impwx
    Разработчик
    Допустим, _inner используется у вас во многих местах, и есть некий публичный метод, который его возвращает. Тогда внешний код сможет вызвать этот метод, получить тот же экземпляр объекта _inner и поставить на него свой lock. Так можно случайно словить взаимоблокировку и повесить приложение.

    Подобные моменты бывает очень сложно отследить, потому объект может быть возвращен косвенно, по интерфейсу, или как-либо еще. Отдельное поле _lock - это просто правило хорошего тона, его создают для безопасности: очень маловероятно, что кому-то придет в голову использовать его за пределами инструкции lock и тем более вернуть из метода.

    Если у вас небольшой код и вы уверены, что знаете, что делаете - разницы нет.
    Ответ написан
    Комментировать
  • Как структура баз данных эффективнее: много записей, много таблиц или много баз?

    petermzg
    @petermzg
    Самый лучший программист
    Лучше: 1 база данных, 6 таблиц, и грамотные индексы.
    Ответ написан
    2 комментария
  • Почему EF не хочет сохранять сущность?

    @dmitrytut
    Используй Bind().To().InRequestScope() вместо Bind().To().InSingletonScope().
    Ответ написан
    Комментировать
  • Есть ли такой реализованный список на 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) });
    Ответ написан
    Комментировать
  • Как в EF настроить одну сущность с двумя внешними ссылками на другую сущность?

    @atticus_finch
    stackoverflow.com/questions/9437366/entity-framewo...
    Я так понял, что у тебя похожая ситуация.
    Ответ написан
    Комментировать