среда, 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