пятница, 14 октября 2016 г.

JavaScript ES5. Пространство имен, наследование, защита от дублирования.

Защита от дублирования скриптов

Следующая функция предотвращает повторную загрузку файла JavaScript

  function scriptLoader(src, callback) {
     "use strict";
      var script = document.querySelector('script[src="'+src+'"]');
      if (script == null) {    
        var head= document.getElementsByTagName('head')[0];
        script= document.createElement('script');
        script.type= 'text/javascript';
        script.src= src;
        script.async = false;
        script.onreadystatechange= function () {
           if (this.readyState == 'complete') callback();
        }
        head.appendChild(script);
      }
      if (script.addEventListener) {
        script.addEventListener("load", callback); 
      } else if (script.attacheEvent) {
        script.addEventListener("onload", callback); 
      } 
  }

Предположим у нас есть следующий скрипт файле alerter.js:

  var Alerter = function() {};
  Alerter.prototype.say = function(smth) { alert(smth); };

Пример использования функции для загрузки alerter.js

  scriptLoader("alerter.js", function() {
    var a = new Alerter();
    a.say("Hi");
  });

  scriptLoader("alerter.js", function() {
    var a = new Alerter();
    a.say("Hi again");
  });

В результате функция выведет в диалоговом окне сначала Hi, затем - Hi again

Функцию можно усовершенствовать, задав на входе массив имен скриптовых файлов.
Также можно модифицировать ее для предотвращения повторной загрузки файлов стилей css.

Предотвращение повторного использования переменных

Для предотвращения повторного использования переменных и ухода от глобального контекста код лучше оборачивать в (function() { //код })();
Например следующий код:

<script>
  var a = 1;
  var v = 2;
</script>

Лучше переписать как:

<script>
(function() {
  var a = 1;
  var v = 2;
})();
</script>

Защита приватных полей

Для защиты приватных полей от внешнего доступа целесообразно использовать конструктор с замыканием. Примерно так:

var MyClass = function() {
  "use strict";
  var _name; // приватная переменная, захватывается функциями getName и setName
  this.getName = function() { return _name}
  this.setName = function(value) {
    _name = value;
  }
 
}

Пример выполнения:

var myObj = new MyClass();
myObj.setName("This is the name");
console.log(myObj.getName()); // Выведет This is the name

Пространство имен

Следующая функция реализует пространство имен из строки, где имена разделены точками. Она возвращает пустой объект

function nameSpace(namespace)
{
  "use strict";
  var parts = namespace.split(".");
  var obj = window;
  for (var i = 0; i < parts.length; ++i) {
    obj[parts[i]] = obj[parts[i]] || {};
    obj = obj[parts[i]];
  };
  return obj;
};

Пример запуска:

   nameSpace("Compsphere.Demo");
   console.log(Compsphere.Demo); //Выводит в консоль Compsphere.Demo

Можно ее использовать и так:

   var obj = nameSpace("Compsphere.Demo");
   obj.NewClass = function() { this.x = "Hi!" }
   console.log((new Compsphere.Demo.NewClass).x); //Выводит в консоль Hi!

Генератор классов с пространством имен

Функцию nameSpace можно модифицировать, превратив ее в генератор классов в некоем пространстве имен.
Вот ее вид:
function createClass(_namespace, _constructor, _prototype) {
  var parts = _namespace.split(".");
  var obj = window;
  for (var i = 0; i < parts.length-1; ++i) {
    obj[parts[i]] = obj[parts[i]] || {};
    obj = obj[parts[i]];
  };

  if (typeof _constructor == "function") {
    obj[parts[i]] = _constructor;
    if (typeof _prototype != "undefined") {
      obj[parts[i]].prototype = _prototype;
    }
  } 
  else {
    obj[parts[i]] = obj[parts[i]] || {};
  }
  return obj[parts[i]];
};

На вход подается пространство имен, функция - конструктор класса и необязательный объект для прототипа. Если конструктор и объект для прототипа не переданы, то createClass отработает аналогично вышеописанной nameSpace. Если не передан только объект для прототипа, то прототип не создастся.

Примеры использования

(function() {
  var myclass = createClass(
    "Compsphere.Demo", 
     function(name) { alert(name) }, 
     {say: function(word) { alert(word); } } 
   ); 

  myclass.prototype.sayAgain = function(word) { alert(word) };
  (new Compsphere.Demo("constructor")).say("Hi");  //Выведет фразу Hi

  var myClassInstance = (new myclass("this is the constructor")); //Выведет фразу this is the constructor
  myClassInstance.say("'say' method"); //Выведет фразу this is the constructor 'say' method
  myClassInstance.sayAgain("'sayAgain' method"); //Выведет фразу 'sayAgain' method
})();

четверг, 28 июля 2016 г.

JavaScript - playing with Canvas. Cellular Automata. Клеточный автомат, играемся с Canvas.

Пример двухмерного клеточного автомата из 6 состояний (0-5) и с начальным состоянием "1" в топ-центре сетки. Каждому состоянию сопоставляется цвет (0 - чёрный, 1 - красный, 2 - синий, 3 - зеленый, 4 - желтый, 5 - белый). В пустой сетке клетки заполняются состоянием "0". Правила переходов (кодовое число) генерируются случайным образом.
Поиграться можно здесь: https://jsfiddle.net/mishau/tja1dpy8/129/

Клеточный автомат

Кодовое число:

пятница, 22 июля 2016 г.

Будущее и настоящее разработки на SharePoint - это чистый JavaScript

Мы занимаемся разработкой на SharePoint для интрасети наших заказчиков и по мере расширения нашей команды, проводим собеседования разработчиков SharePoint developers. В настоящее время, историческому разработчику SharePoint, который работает с C#, ASP.NET, фермерскими решениями, и т.п., приходят на смену разработчики, которые видят SharePoint и Office 365, просто как еще одну платформу JavaScript для веб. Когда мы собеседуем разработчиков SharePoint, мы спрашиваем их об их опыте работы с фреймворками JavaScript, стилями CSS styling, модульным дизайном MVVM и работе с JSOM, REST, и т.п. В данный момент мы нанимаем людей, у которых есть опыт работы с CSS, HTML и фреймворками JavaScript, такими как Knockout JS, Angular, React, и т.п., так как это является видом кастомизации, который мы осуществляем. В последнее время мы не занимаемся активной разработкой на C#, за исключением тех клиентов, которые все еще используют предыдущие версии SharePoint и хотят мигрировать на SharePoint 2016, но сохранив свои существующие фермерские решения, свои рабочие процессы, формы InfoPath, и т.д. Microsoft стимулирует (такой) переход от разработки на серверной стороне к разработке на клиентской стороне уже как несколько лет, начиная с SharePoint 2010 и значительно форсированы с Office 365. Когда Office 365 исключил фермерские решения и серверный код, разработчики перешли на 100% клиентскую разработку с применением JavaScript, HTML, CSS, и т.д. В SharePoint 2016 вы пока еще можете использовать C# или ASP.NET для создания фермерских решений, но главным образом это оставлено для обратной совместимости. Чтобы решение поддерживало, как Office 365, так и SharePoint 2016 рекомендуется использовать кастомизацию только на клиентской стороне.

В выходящем в ближайшее время SharePoint Framework, Microsoft даже еще глубже продвигается в мир JavaScript. Исчезнувшие веб-части / апп-части / и расширения типа контейнеров компонентов IFrame, уступили место встроенным Add-in расширениям JavaScript, которые динамически подключаются к странице. Эти расширения JavaScript могут быть либо развернуты в Office 365, либо загружены из внешней CDN. Фреймворк SharePoint использует 100% кода JavaScript и такие инструменты, как TypeScript, Node.JS, React, JSON, и Gulp для построения кастомизаций. В отличие от текущей модели Add-in, код включается непосредственно в веб-страницу без каких-либо старых контейнеров, базирующихся на IFrame, которые используются в более старых версиях SharePoint.

Если вы являетесь одним из разработчиков SharePoint/C, которые по-прежнему думают, что JavaScript это язык второго сорта, подумайте еще – он должен восприниматься, как первоклассный язык. Microsoft его усиленно продвигает, и разработка на SharePoint, сейчас в основном, является разработкой на клиентской стороне и будет продолжать оставаться таковой в будущем.


Перевод статьи For SharePoint Development, the Future (and Present) is Clearly JavaScript

четверг, 30 июня 2016 г.

Печальное известие

7 июня в Нижнекамске в автокатастрофе в возрасте 34 лет трагически погиб мой бывший коллега по Softline, ближайший сосед в офисе по креслу, руководитель отдела региональных продаж Департамента решений Microsoft Александр Громыко.

Саня всегда был очень веселым парнем.

Буду помнить...

вторник, 19 апреля 2016 г.

Остаток от деления без % в C#. Анализ алгоритмов.

Итак, на собеседовании по C# время от времени попадается задача нахождения остатка от деления (число R) целочисленных положительных чисел M и N без применения оператора %;

Алгоритмы

Первое, что приходит в голову, это следующая формула:

    R = M-M/N*N

Второе, что приходит в голову, это стандартная функция в лоб:

i = 0;
do {
i++;
r = m-n*i;

} while (r>=n)
return n;

Третье. предыдущий алгоритм можно ускорить, путем удвоения удвоения. Назовем это интеллектуальным алгоритмом. Мы удваиваем i, и если остаток будет отрицательный, то мы возвращаемся к предыдущему шагу, но с учетом достигнутого результата. И начинаем все заново.

i = 1;
k = 0;


while (true)
{ r = m - (k + i) * n;

if (r >= 0 && r < n)
{
return r;
}

if (r > 0)
{
i *= 2;
}
else
{
k += (i / 2);
i = 1;
}
}

Исходные коды методов для "стандартного" и "интеллектуального" алгоритмов:

Стандартный
        static int StdReminder(int m, int n)
        {
            if (m < n)
            {
                return m;
            }

            var i = 0;
            var r = 0;
            do 
            {
                i++;
                r = m - i * n;
            } while (r >= n)
            return r;
        }
Интеллектуальный
        static int IntelReminder(int m, int n)
        {

            if (m < n)
            {
                return m;
            }

            var i = 1;
            var k = 0;


            while (true)
            {
                var r = m - (k + i) * n;

                if (r >= 0 && r < n)
                {
                    return r;
                }

                if (r > 0)
                {
                    i *= 2;
                }
                else
                {
                    k += (i / 2);
                    i = 1;
                }
            }

       }

Код для тестирования времени выполнения:

        static void Main(string[] args)
        {
            var rnd = new Random();

            var m = rnd.Next(3, 100000000);
            var n = rnd.Next(1,  19);

            var sw = Stopwatch.StartNew();
            var r = m % n;
            sw.Stop();
            Console.Write("Operator M % N:     ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());

            sw = Stopwatch.StartNew();
            r = m - m/n*n;
            sw.Stop();
            Console.Write("Operator M - M/N*N: ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());


            sw = Stopwatch.StartNew();
            r = StdReminder(m, n);
            sw.Stop();
            Console.Write("Standard Func:      ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());


            sw = Stopwatch.StartNew();
            r = IntelReminder(m, n);
            sw.Stop();
            Console.Write("Intellectual Func:  ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());

            Console.ReadKey();
        }

Анализ результатов

Вот, что у меня получилось в консоли

Operator M % N: 17485844 % 13 = 12; Time: 00:00:00.0000009
Operator M - M/N*N: 17485844 % 13 = 12; Time: 00:00:00.0000003
Standard Func: 17485844 % 13 = 12; Time: 00:00:00.0037792
Intellectual Func: 17485844 % 13 = 12; Time: 00:00:00.0001679

Выводы:

- Самым быстрым оказался алгоритм M-M/N*N. Он работает в три раза быстрее, чем стандартный оператор %;
- Самый худший - это "стандартный" алгоритм, он дает существенно большее время, чем все прочие.
- "Интеллектуальный" алгоритм работает примерно в 22 раза быстрее, чем "стандартный" и в 560 раз медленнее, чем формула M - M/N*N.

воскресенье, 17 апреля 2016 г.

Singleton в C#

В этом посте мы рассмотрим следующие вещи :

  • Что такое паттерн проектирования Singleton (одиночка) ?
  • Как запрограммировать "одиночку" в C# ?
  • Эффекты многопоточности на паттерне Singleton
  • Реализация двойной блокировки при программировании "одиночки"
  • Раннее создание экземпляра "одиночки"
  • Полноценное "ленивое" создание "одиночки"
  • Программирование "одиночки" с применением обобщений С#
  • Создание одиночки через Lazy<T>
  • Пути взлома "одиночки"
  • Использование "одиночки"
  • Singleton как антипаттерн
  • Различия между статическим классом и паттерном Singleton
  • Заключение

Паттерн проектирования Singleton:

Шаблон (паттерн) проектирования Singleton гарантирует единственность экземпляра класса и предоставляет глобальный доступ к его свойставм и методам.

Стандартная реализация шаблона Singleton

Чтобы создать ровно один экземпляр "одиночки", мы делаем конструктор приватным. Теперь мы можем инстанцировать класс только внутри самого класса.
Мы создаем статическое поле, которое будет содержать созданный экземпляр класса.
Затем мы создаем статический метод, который представляет экземпляр класса для внешнего доступа. В методе проверяется существует ли экземпляр класса, и если нет, то создает и возвращает его, а в противном случае просто возвращает созданный ранее объект.

 private static Singleton _instance;
 
 private Singleton() {}
 
 public static Singleton GetInstance()
 {

  if(_instance == null)
                {
   _instance = new Singleton();
  }
  return _instance;

 }

Проблемы со стандартной реализацией

Стандартная реализация прекрасно работает в однопотоковой среде. В многопотоковой среде метод GetInstance() даст сбой :

public static Singleton GetInstance()
{

   if(_instance == null)
   {
      _instance = new Singleton();

   }
  return _instance;
}
Если два потока вызовут условие в операторе "if" в один и тот же момент времени, то будет создано два экземпляра класса Singleton.

Решение проблемы многопоточности в стандартной реализации одиночки

Мы можем синхронизировать код метода таким образом, что только одна нить будет владеть кодом в один момент времени. В коде ниже нить блокирует объект и проверяет, не был ли уже создан ранее экземпляр объекта.

  public sealed class Singleton
    {
        private static Singleton _instance = null;
        private static readonly object _lock = new object();
 
        private Singleton() {}
 
        public static Singleton GetInstance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                    }
                    return _instance;
                }
            }
        }
}
Такой код решает проблему. Но это замедляет работу, потому что все прочие потоки ожидают завершения блокировки. Для этого мы используем следующие подходы :

1 : Двойная проверка при блокировке

Этот подход предусматривает изначальное существование экземпляра, и если экземпляр не существует, создает его под блокировкой.

 public sealed class Singleton
    {
        private static Singleton _instance = null;
        private static readonly object _lock = new object();
 
        private Singleton() {}
 
        public static Singleton GetInstance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lock)
                    {
                        if (_instance == null)
                        {
                            _instance = new Singleton();
                        }
 
                    }
                }
                return _instance;
            }
        }
   }
Примечание. Подобный вопрос попался мне на экзамене по С# на сертификат Microsoft.

2 : Заранее созданный экземпляр

Здесь мы создаем экземпляр "одиночки" во время загрузки класса. Потокобезопасность осуществляется в этом случае без блокирования кода оператором lock.

public class Singleton 
{
 //создание экземпляра немедленно
 private static Singleton _instance = new Singleton();
 
 private Singleton() {}
 
 public static Singleton Default
 {
     get { return _instance; } //просто возвращаем экземпляр
 }

}

3 : Полноценное отложенное создание экземпляра

В этом примере инстанцирование происходит при первом обращении к статическому свойству Default класса Singleton.

 public sealed class Singleton
  {
    private Singleton()
    {
    }
 
    public static Singleton Default { get { return GetInstance._instance; } }
        
    private class GetInstance
    {
        // Явный статический конструктор сообщит компилятору
        // не инициализировать поле заранее
        // и поле будет инициализировано при первом к нему обращении 
        static GetInstance()
        {
        }
 
        internal static readonly Singleton _instance = new Singleton();
    }
 }
 

4 : Реализация паттерна Singleton с применением обобщений

Здесь будет создан единственный экземпляр и загрузка эффективно будет отложена, потому что конструктор не вызовется пока не будет вызван Build().

 public class Singleton<T> where T : new()
    {
        private static T _instance = new T();
 
        public T Default()
        {
            get { return _instance; }
        }
    }
 
...
    Singleton<SimpleType> instance = new Singleton<SimpleType>();
    SimpleType simple = instance.Default;

5 : Применение Lazy<T> type

Передавая в конструктор Lazy делегат (или, что проще, лямбда-выражение), в котором вызывается конструктор одиночки, мы получаем отложенное создание экземпляра.

public sealed class Singleton
{
    private static readonly Lazy<Singleton> _lazy =
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Default{ get { return _lazy.Value; } }
 
    private Singleton()
    {
    }
}

Обходные пути для взлома Singleton - вопросы, которые задают на собеседовании :

Даже если мы предотвратим создание нескольких экземпляров,используя двойную проверку при блокировке или мгновенное создание экземпляра, экземпляры все равно можно будет создать через :

– клонирование
– рефлексия
– использование класса singleton в качестве подкласса

Как избежать создания экземпляра Singleton через клонирование объекта ?

Через метод clone() можно создать копию объекта.

Чтобы предотвратить создание клонов экземпляра "одиночки", необходимо сделать следующее :

– Реализовать метод MethodwiseClone()
– Переопределить метод clone() и возбудить оттуда исключение CloneNotSupportedException.
 protected object MemberwiseClone()
    {
        throw new Exception("Cloning a singleton object is not allowed");
    }

 

Как предотвратить создание экземпляра Singleton через рефлексию ?

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

 private Singleton()
    {
        if (_instance != null)
        {
            throw new Exception("Cannot create singleton instance through reflection");
        }
    }

 

Как предотвратить создания экземпляра "одиночки" в качестве подкласса ?

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

Для чего используется паттерн проектиорвания Singleton :

Логирование :

Шаблон Singleton хорошо подходит для реализации протоколирование, если мы планируем единственный файл лога для всех сообщений.

Кеширование:

Шаблон Singleton может быть использован в реализации механизма кеширования для предоставления глобального доступа к кешу.

Почему "одиночка" считается антипаттерном?

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

Отличия "одиночки" от статического класса :

– В C# в статическом классе нельзя реализовать интерфейс. В случае, если "одиночка" должен реализовать интерфейс, например для использования в IoC, вы можете не использовать статический класс
– Singleton можно клонировать, объект статического класса клонировать нельзя
– Объект Singleton хранится в куче, статический - в стеке
– Можно реализовать отложенную или асинхронную инициализацию "одиночки", а статический класс инициализируется при первой загрузке.

Заключение:

Итак, мы обусдили:
  • Различные способы программирования синглтона в C#
  • Использование паттерна синглтона
  • Почему синглтон является антипаттерном?
  • Различия между статическим классовм и синглтоном

воскресенье, 3 апреля 2016 г.

Распределение ролей в команде разработчиков SharePoint

При работе над проектами SharePoint, в команде разработчиков целесообразно распределить следующие роли:
  1. Руководитель проекта: Ведет проект до успешного внедрения посредством зарекомендовавших себя методологий.
  2. Архитектор: Технический специалист, который отвечает за концептуальную разработку решения в целом, взаимодействуя с остальными командными игроками.
  3. Инфраструктурщик и/или
  4. Разработчик: Расширяет возможности SharePoint посредством кодирования или встраиванием скриптов / кода наподобие кастомизации (JavaScript, XML, и т.п)
  5. Конфигураст: Его главной задачей является конфигурирование SharePoint и выкладывание страниц без написания кода. Разумеется, вы как разработчик или инфраструктурщик можете все это сделать и сами, но стоит ли это средств, потраченных на оплату вашего труда?
  6. Дизайнер/Информационный архитектор: На больших проектах могут быть заняты занимаются два разных специалиста. На средних проектах один человек может успешно справляться с двумя ролями, тем более после надлежащего обучения. Дизайнер UX представляет решение с точки зрения пользователя, разбираясь в том, как пользователи будут работать с сайтом, а затем проектируя навигацию, переходы между страницами, разметку страниц. Информационный архитектор анализирует суть информации, которую вы собираетесь хранить на данный момент или в будущем, а также предлагает к рассмотрению информацию, которую вы не планировали пока хранить, а затем разрабатывает такие вещи, как типы контента, метаданные, поля, значения, контролы и т.п. для структурирования и управления такой информацией.
  7. Производитель контента: Известные последние слова множества неудачных проектов на SharePoint звучат примерно так: “Не беспокойтесь, контент находится под контролем.” Хороший проект на SharePoint требует, чтобы кто-то отвечал за то, что полезный контент был своевременно создан и добавлен. Заметьте: лучшие решения требуют исполнения этой роли от многих людей.

суббота, 2 апреля 2016 г.

Структура решения SharePoint в Visual Studio

Одним из способов успешного создания решения SharePoint является разбиение решения на отдельные зависимые проекты:

  • Branding
    В данном проекте находятся все файлы, относящиеся к UI - пользовательскому интерфейсу, в первую очередь изображения и стили css. С этим проектом в основном имеет дело разработчик UI/UX. Как правило в проекте не должно содержаться ни одной строчки кода .NET, что означает отсутствие сборок для развертывания.
  • Presentation
    В этом проекте должны находиться веб-части, мастер-страницы, страницы приложения (application pages), элементы управления, и т.п. Это в первую очередь компоненты, которые могут быть исплозованы в разных частях решения. Проект не должен явно зависеть от проекта Branding.
  • Definition
    Этот проект содержит типы, столбцы сайта, типы полей, определения списков (list definitions) и сайтов (site definitions), а также шаблоны web. Проект имеет зависимость от проектов Presentation и Branding
  • Core
    Этот проект содержит, как правило, единственную сборку, которая представляет главную функциональность, используемую другими проектами. Это можно воспринимать, как бибилиотеку утилит или класс бизнес-логики. В большинстве случаев, проект не должен содержать никаких артефактов SharePoint. Исключение могут составлять файлы JavaScript, которые выступают как утилиты.
  • Resources
    Здесь содержатся все файлы языковых ресурсов, используемых остальными проектами. Оформив их в виде отдельного проекта, вы упростите перевод и организацию ресурсов для всего решения.
  • Others
    Прочие проекты, в зависимости от типа решения. Предположим, проект для рабочих процессов (workflows).

Как вы возможно заметили, при разработке решения в виде подобной структуры, могут возникнуть проблемы среди разработчиков, работающих на одном проекте. В первую очередь это касается добавления и удаления файлов, потому что при этом происходит обновления файла проекта csproj. Здесь на помощь придет система контроля версий TFS и т.п., что поможет наладить необходимый мерджинг.

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

Создание нескольких WSP для одного решения также потребует некоторой стандартизации развертывания, позволяющей проконтролировать пререквизиты при установке решения. Имеется множество скриптов для развертывания, доступных на CodePlex. Если вам интересно, гляньте проект "SharePoint Solution Deployer" по ссылке http://spsd.codeplex.com

среда, 17 февраля 2016 г.

Что исчезнет в .NET Core


Следующие компоненты из списка перекочуют в решения с открытым исходным кодом, так как не будут входить в ядро .NET Core.

  • System.Data. Хоть поддержка на базовом уровне и есть в .NET Core, такая как модель провайдеров и SQL client, кое-что сейчас недоступно, например поддержка схем и типов DataTable/DataSet.
  • System.DirectoryServices. Сейчас в .NET Core нет поддержки для LDAP или Active Directory.
  • System.Drawing. Хотя, строго говоря, System.Drawing является клиентским API, многие разработчики используют этот API на серверах для генерации иконок или водяных знаков. Но теперь это отсутствует в .NET Core.
  • System.Transactions. Мы знаем, что ADO.NET поддерживает транзакции, однако в Core нет поддержки распределенных транзакций.
  • System.Xml.Xsl и System.Xml.Schema. В .NET Core поддерживается XmlDocument и Linq-To-XML (XDocument), включая XPath. Тем не менее, отсутствует поддержка для XSD (XmlSchema) или XSLT (XslTransform).
  • System.Net.Mail. Не имеется поддержка отправки электронной почты из .NET Core с применением данных API.
  • System.IO.Ports. Поддержка работы с серийным портом отсутствует в .NET Core.
  • System.Workflow. Windows Workflow Foundation (WF) не доступен в .NET Core.
  • System.Xaml. Создавая приложения UWP, используют API WinRT XAML. Однако, в текущий вариант .NET Core не включен управляемый каркас XAML, у которого есть возможность обрабатывать документы XAML и создавать графы описанных в них объектов.

понедельник, 8 февраля 2016 г.

SPList Items и GetItems

Продолжаем исследовать исходный код некоторых компонент SharePoint. В этот раз посмотрим различия между свойством SPList.Items и методом SPList.GetItems()
// Microsoft.SharePoint.SPList
public SPListItemCollection GetItems(params string[] fields)
{
 if (fields == null)
 {
  throw new System.ArgumentNullException("fields");
 }
 System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
 for (int i = 0; i < fields.Length; i++)
 {
  string text = fields[i];
  if (text != null)
  {
   stringBuilder.Append("");
  }
 }
 return this.GetItems(new SPQuery
 {
  ViewAttributes = "Scope=\"Recursive\"",
  ViewFields = stringBuilder.ToString()
 });
}

// Microsoft.SharePoint.SPList
/// Returns a collection of items from the list based on the specified query.
/// An  object that represents the items.
/// An  object that contains the query.
[ClientCallable]
public SPListItemCollection GetItems([ClientCallableConstraint(Type = ClientCallableConstraintType.NotNull)] SPQuery query)
{
 return new SPListItemCollection(this, query);
}

// Microsoft.SharePoint.SPList
/// Gets the number of items in the list.
/// A 32-bit integer that indicates the number of items.
[ClientCallable, ClientCallableConstraint(Type = ClientCallableConstraintType.Custom, FixedId = "a", Value = "It MUST be a greater than or equal to zero.")]
public int ItemCount
{
 get
 {
  this.EnsurePropsFresh();
  return (int)this.m_arrListProps[(int)((System.UIntPtr)20), (int)((System.UIntPtr)this.m_iRow)];
 }
}

воскресенье, 7 февраля 2016 г.

Корректное получение элементов списка в Task.Run


Итак, нам надо осуществить загрузку элементов списка в другой нити, для чего можно воспользоваться методом Task.Run. Однако, "в лоб" воспользоваться этим методом не удастся, так как потокобезовасность экземпляров SPWeb, как и многих других объектов не гарантируется.

Thread safety

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Поэтому следующий код приведет к исключению SPException с внутренним кодом 0x80010102 - ошибка потоков.
private SPWeb _web;

..............................

SPListItemCollection items;

var task1 = Task.Run(() =>
  {
    items = web.GetList(@"Lists\List1").GetItems.OfType();
  })

Решением будет являться создание нового экземпляра SPWeb внутри потока:

private SPWeb _web;

...........................

SPListItemCollection items;

var task1 = Task.Run(() =>
  {
    using (var web = _web.Site.OpenWeb())
    {
       items = web.GetList(@"Lists\List1").GetItems.OfType();
    }
  });

суббота, 6 февраля 2016 г.

Что делают SPWeb.Dispose() и Close()?


Вскрытый код метода Microsoft.SharePoint.SPWeb.Dispose();
// Microsoft.SharePoint.SPWeb
public void Close()
{
 if (this.m_closed)
 {
  return;
 }
 if (this.m_bFirstUniqueAncestorWebInited && this.m_FirstUniqueAncestorWeb != null && !object.ReferenceEquals(this.m_FirstUniqueAncestorWeb, this))
 {
  this.m_FirstUniqueAncestorWeb.Dispose();
  this.m_bFirstUniqueAncestorWebInited = false;
  this.m_FirstUniqueAncestorWeb = null;
 }
 if (this.m_Site != null)
 {
  if (this == this.m_Site.m_rootWeb)
  {
   this.m_Site.m_rootWeb = null;
  }
  this.m_Site.InvalidateWeb(this);
 }
 if (this.m_ctsAll != null)
 {
  foreach (SPContentType sPContentType in this.m_ctsAll)
  {
   sPContentType.CloseWebAsNecessary();
  }
 }
 this.Invalidate(SPContentTypeClass.Field);
 this.Invalidate(SPContentTypeClass.Type);
 if (this.m_Site != null)
 {
  this.m_Site.RemoveFromOpenedWebs(this);
 }
 this.Invalidate();
 this.m_closed = true;
}

[SharePointPermission(SecurityAction.Demand, ObjectModel=true)]
public void Dispose()
{
  this.Close();
}

До кучи System.IO.StreamWriter.Dispose():

// System.IO.TextWriter
/// Освобождает все ресурсы, используемые объектом .
public void Dispose()
{
 this.Dispose(true);
 GC.SuppressFinalize(this);
}
// System.IO.StreamWriter
/// Закрывает текущий объект StreamWriter и базовый поток.
/// Текущая кодировка не поддерживает отображение половины суррогатной пары Юникода.
/// 1
public override void Close()
{
 this.Dispose(true);
 GC.SuppressFinalize(this);
}
// System.IO.StreamWriter
/// Освобождает неуправляемые ресурсы, используемые  (при необходимости освобождает и управляемые ресурсы).
/// 
///           Значение true позволяет освободить управляемые и неуправляемые ресурсы; значение false позволяет освободить только неуправляемые ресурсы. 
/// Текущая кодировка не поддерживает отображение половины суррогатной пары Юникода.
protected override void Dispose(bool disposing)
{
 try
 {
  if (this.stream != null && (disposing || (!this.Closable && this.stream is __ConsoleStream)))
  {
   this.Flush(true, true);
   if (this.mdaHelper != null)
   {
    GC.SuppressFinalize(this.mdaHelper);
   }
  }
 }
 finally
 {
  if (this.Closable && this.stream != null)
  {
   try
   {
    if (disposing)
    {
     this.stream.Close();
    }
   }
   finally
   {
    this.stream = null;
    this.byteBuffer = null;
    this.charBuffer = null;
    this.encoding = null;
    this.encoder = null;
    this.charLen = 0;
    base.Dispose(disposing);
   }
  }
 }
}
И еще до кучи (System.Data.SQLClient.SQLConnection.Dispose()):
protected override void Dispose(bool disposing)
{
  if (disposing)
  {
      this._userConnectionOptions = null;
      this._poolGroup = null;
      this.Close();
  }
  this.DisposeMe(disposing);
  base.Dispose(disposing);
}

понедельник, 1 февраля 2016 г.

Новые возможности C# 6.0

Перевод статьи New Features of C# 6.0

В этой статье мы познакомимся с новыми ключевыми фишками и усовершенствованиями, появившимися в C# 6.0.

Автоматически реализуемые свойства:

Эта штука позволяет нам задать значения свойств на этапе их объявления.
Previously, we use constructor to initialize the auto properties to non-default value but with this new feature in C# 6.0, it doesn’t require to initialize these properties with a constructor aкак показано ниже:

class Customer
{
    public string Firstname{get; set;} = "Csharpstar";
    public string Lastname{get; set;} = "Admin";
    public int Age{get;} = 20;
    public DateTime BirthDate { get; set; }
}
We can use this property with getter/setter and getter only.Using getter only help achieve immutability.

Фильтры исключений:

Microsoft introduced this CLR feature in C# with version 6.0 but it was already available in Visual Basic and F#. To use Exception Filters in C#, we have to declare the filter condition in the same line as that of the catch block and the catch block will execute only if the condition is successfully met as shown below:

try
{
throw new CustomException("Test Exception")
}
catch(CustomException ex) if (ex.Message=="Not Test")
{
//Control will not come here because exception name is not test
}
catch(CustomException ex) if (ex.Message=="Test Exception")
{
//Control will come here because exception name is Test Exception
}
 
Remember that Exception Filter is a debugging feature rather than a coding feature. We will discuss more on this in next post

Await в блоках catch и finally block:

We frequently log exceptions to a log file or a database. Such operations are resource extensive and lengthy as we would need more time to perform I/O. In such circumstances, it would be great if we can make asynchronous calls inside our exception blocks. We may additionally need to perform some cleanup operations in finally block which may also be resource extensive.

try
{
// code that might throw exception
}
catch(Exception ex)
{
await LogExceptionAsync(ex);
}

Getter-only Auto Properties

When you use auto implemented properties in C# 5 and lower, you must provide a get and set. If you want the property value to be immutable, you can use the private accessor on the setter. With C# 6, you can now omit the set accessor to achieve true readonly auto implemented properties:

 
public DateTime BirthDate { get; }

Интерполяция строк

String.Format was used till today to generate the FullName value in the Customer class.A new feature named string interpolation provides a large improvement in this area. Rather than filling placeholders with indexes provide an array of values to be slotted in at runtime, you provide the source of the parameter value instead, and the string.Format call is replaced by a single $ sign. This is how the FullName property declaration looks when using string interpolation in the expression body instead:

 
public string FullName => $"{FirstName} {LastName}";
Apart from this saving a number of key strokes, it should also minimise (if not remove) the possibility of FormatExceptions being generated from inadvertently supplying too few values to the argument list.

Инициализация словарей:

В C# 6.0 появился более прозрачный путь для инициализации словарей (см. ниже):

 
var BookDictionary = new Dictionary<int,string>
{
[1] = "ASP.net",
[2] = "C#.net",
[3] = "ASP.net Razor",
[4] = "ASP.net MVC5"
}
А раньше было так:
Dictionary<int,string> BookDictionary = new Dictionary<int,string>()
{
{1, "ASP.net"},
{2, "C#.net"}
{3, = "ASP.net Razor"},
{4, = "ASP.net MVC5"}}
};

Null – условный оператор:

Null-условный оператор “?” использует одинарный знак вопроса. It can be used to reduce the no. of lines in code file and provide an easy access to check for Null and return the result. The null conditional operator tests for null before accessing a member of an instance. Пример:

using System;

class Program
{ static void Test(string name)
    {
 // Use null-conditional operator.
 // ... If name is not null, check its Length property.
 if (name?.Length >= 3)
 {
     Console.WriteLine(true);
 }
    }
    static void Main()
    {
 Console.WriteLine(1);
 Test(null);
 Console.WriteLine(2);
 Test("Csharpstar"); // True.
 Test("x");
 Test("ExamIron"); // True.
    }
}
Выводится:1
2
True
True

воскресенье, 31 января 2016 г.

Даинамическое отображение полей при вставке записей в список (без SharePoint Designer)

Итак, имеются два вида пользователей - физическое лицо, юридическое лицо. Это хранится в поле выбора "Форма оплаты". В зависимости от выбора формы оплаты из выпадающего списка, нужно отображать соответствующие данные: ФИО, паспорт для физлица и реквизиты для юрлица. Для этого:

1) Заходим в список, выбираем в ленте "Список" -> "Веб-части формы" ->Форма создания по умолчанию".

2) Загрузится форма. Затем нажимаем в верхней панели "Добавить веб-часть" и из группы "Среди и контент" выбираем веб-часть "Редактор контента".

3) Далее нажимаем кнопку "Добавить" и кликаем на поле редактора в самой веб-части.

4) В ленте появятся иконки редактирования контента. Где-то справа в конце будет иконка "HTML".

5) Жмем на иконку в в окно вводим следующий скрипт (см. ниже);

6) Сохраняем изменения для веб-части

7) Всё.

 
Особенность: Ввиду того что поиск производится по атрибуту Title, по началу строки, от атрибут Title одного поля не должен полностью входить в атрибут Title другого поля.
Дополнительно

Открытие диалогового окна на вставку записи из навигационной панели.

Открытие диалогового окна на вставку из навигационной панели.

1) Действия сайта -> Параметры сайта -> Внешний вид и функции ->Верхняя панель ссылок или адрес  http://myserver/_layouts/topnav.aspx

2) Далее жмем "Создать ссылку для перехода"

3) В поле "Введите описание" пишем название в горизонтальном пункта меню.

4) В поле "Введите веб-адрес" пишем адрес следующий java-скрипт одной строкой:

JavaScript:var options=SP.UI.$create_DialogOptions();options.url='http://myserver/Lists/List1/NewForm.aspx';options.height = 800;void(SP.UI.ModalDialog.showModalDialog(options))
Вместо адреса http://myserver/Lists/List1/ указываем свой адрес списка

суббота, 30 января 2016 г.

10 частых вопросов на собеседовании по C# на числа


  1. Как поменять два числа местами в C# без использования временной переменной (Решение)

  2. Write a C# program to determine total ways stairs can be climbed (Решение)

  3. Напишите программу на C# для вычисления факториала без рекурсии (Решение)

  4. Напишите на C# программу вывода n-го числа чисел Фибоначчи (Решение)

  5. Напишите на C# программу получения остатка от деления 2-х целых (Решение)

  6. Напишите на C# программу, проверяющую является ли введенное число числом Армстронга (Решение)

  7. Напишите на C# программу поиска НОК и НОД для 2-х заданных чисел. (Решение)

  8. Напишите на C# программу, проверяющую является ли введенное число простым (Решение)

  9. Напишите на C# программу, проверяющую является ли введенное число Палиндромом (Решение)

  10. Напишите на C# программу, решающую проблему FizzBuzz (Решение)