Показаны сообщения с ярлыком .NET. Показать все сообщения
Показаны сообщения с ярлыком .NET. Показать все сообщения

вторник, 24 мая 2011 г.

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


  1. Всё также незаменима библиотека DotNetOpenAuth. OpenID и OAuth в одном флаконе, клиент и сервер.
    Разнообразные сервисы начинают предоставлять API и авторизацию часто делают именно через OAuth (разных версий, 1.0 и 2.0). Всё покрывает DNOA.
  2. Продолжая тему API - большинство вендоров предоставляют доступ на основе идеологии REST.
    Мой новый конёк для взаимодействия с такими сервисами - RestSharp.
  3. А данные через REST гоняются преимущественно в формате JSON. Json.NET всё также хорош.
  4. Протокол REST - stateless. Асинхронное взамодействие великолепно кладется на эту парадигму и позволяет на том-же железе обрабатывать бо́льшое количество запросов.
    Но делать это - сложно и муторно. Reactive Extensions спешат на помощь!
  5. Да, данные-то надо хранить у себя. Приходят они к нам в JSON, зачем их во что-то конвертировать? Так и будем хранить! Новый тренд - NoSQL, документоориентированные базы данных. Я выбрал MongoDB и библиотеку NoRM для доступа из C# (поддержка LINQ в коробке). До сих пор до конца не всё понятно и идеолоигически ясно, но определенно, за этим будущее.
А для чего весь этот набор библиотек? Я попробовал и поигрался с разными API сервисов (так ничего практичного и не вышло пока :) ). Весь этот арсенал позволяет свести все технические сложности (большинство ;) ) к минимуму и сосредоточитсья именно на идее/задаче.

Вот лишь небольшой список сервисов, я с которыми я работал:

воскресенье, 14 июня 2009 г.

Кодогенерация T4

Нет, это не про Терминатора :)
Это про использование T4 Text Template Transformation Toolkit, встроенного в Visual Studio 2008 для автоматической генерации кода.
Кратко задача – есть исходники. Опять-то таки сгенерированные, но другим инструментом, Thrift.
Код на C#, публичные поля и свойства в классах с одинаковым именем, только различаются регистром.
Код необходимо использовать из VB.NET. Упс! VB.NET нечувствителен к регистру! Приплыли.
Исходники конечно есть, но они регулярно обновляются – так что их исправлять нельзя.
Классы не помечены partial – расширить напрямую тоже нельзя.
Но у нас же есть extension методы – спасибо .NET 3.5! Можно понаписать методов (эх… пока только методы, эктеншен свойств нет) с названием совпадающим со свойствами, но с каким-нибудь префиксом, подчеркиванием например.
Ок, хорошо. Но вручную писать обертки на 20 классов?! Да они еще, как я сказал, могут обновиться в будущем. Тут нужна автоматизация… И в VS 2008 она уже встроена – движок кодогенерации T4.
Файлы с расширением tt. Синтаксис очень похож на ASP.NET, только исполняются внутри Visual Studio (и не только, хостом может выступать любое приложение, и ваше в том числе).
И вот всё волшебство:

<#@ template language="C#v3.5" hostspecific="true" #>
<#@ assembly name="EDAM.dll" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="Evernote.EDAM.Type" #>

// Autogenerated by <#= Host.GetType() #>
// <#= DateTime.Now #>
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING

namespace Evernote.EDAM.Type
{
<# foreach (var @class in Assembly.GetAssembly(BaseClass)
              .GetExportedTypes()
              .Where(type => !type.IsNested)
              .Where(type => type.Namespace == BaseClass.Namespace)) { #>
  public static class <#= @class.Name #>Ex
  {
  <# foreach (var prop in @class.GetProperties()) { #>
    public static <#= PrintType(prop.PropertyType) #> _<#= prop.Name #>(this <#= prop.DeclaringType #> value)
    {
      return value.<#= prop.Name #>;
    }
  <# }#>
  }
<# } #>
}
<#+ Type BaseClass = typeof(Note); #>
<#+
public string PrintType(Type type)
{
  var typeExpr = new CodeTypeReferenceExpression(type);
  var csProvider = Microsoft.CSharp.CSharpCodeProvider.CreateProvider("C#");
  var writer = new StringWriter();
  csProvider.GenerateCodeFromExpression(typeExpr, writer, new CodeGeneratorOptions());
  return writer.ToString();
} #>


Вкратце, по шагам:
  1. Перебираем все классы из сборки, из нужного пространства имен.
  2. Для каждого класса генерируем статический класс с таким-же именем и суффиксом Ex.
  3. Перебираем все свойства класса.
  4. Генерируем экстеншен-метод нужного типа с именем как оригинальное ствойство, но с префиксом _.
  5. Для генерация имени нужного типа используется маленькая хитрость. Так как по простому дженерики будут выводиться в IL-нотации, т.е. например System.Generic.List’1[System.String]. И это не будет компилироваться. Надо System.Generic.List<System.String> (для C#). Что и делается через CodeDom. Так как сборка на C# – то и провайдер для C# используется. Можно генерировать и в VB. Как в CodeDom, так и в самом T4 кстати.
Всё, теперь при сборке будет генерироваться набор расширений для каждого нужного класса с методами дублирующими все свойства, которые уже без проблем можно использовать в VB.NET. Кстати, в VB можно опускать скобки при вызове метода, если он не принимает параметров, что делает код еще более изящным (насколько вообще можно говорить об изящности в этой ситуации):

C# note.Attributes.Lattitude


VB.NET note._Attributes._Lattitude


Полезные ссылки:

пятница, 15 мая 2009 г.

Яндекс.Фотки API

Яндекс.Фотки наконец-то открыли официальный API. Базирован на AtomPub.
Решил перевести существующие решения для Яндекс.Фоток на него (Picasa, Архив, WLW, WLPG).

Для работы с AtomPub в .NET попробовал несколько вариантов:

  1. System.ServiceModel.Syndication из .NET 3.5
    Базовые сущности ServiceDocument, AtomFeed, AtomEntry.
    Но все изменяющие операции (Insert, Update, Delete) приходится делать врукопашную, через WebRequest.

  2. Microsoft.Web.AtomPub
    Небольшая надстройка над первым пунктом из Live Framework SDK. Негибкая, на некоторых операциях с сервером от Яндекса давится.

  3. AtomSite
    Как оказалось, это серверная имплементация AtomPub, не клиент.

  4. GData .NET Client Library
    Предназначается для работы с сервисами Гугла, но есть базовая библиотека для работы с AtomPub, непривязанная к особенностям Гугла. Немного перегружена, но довольна гибкая и в исходниках!



После экспериментов остановился на последнем. Очень мне нравится конвергенция в современном мире - я объединяю двух непримиримых конкурентов.


namespace Team23.YandexFotki
{
  public class YaDataRequest : GDataRequest
  {
    ...
  }
}

суббота, 20 декабря 2008 г.

Типизированный путь к действию контроллера в ASP.NET MVC

В ASP.NET MVC для генерации путей (url) для действий (action) контроллеров (controller) можно использовать методы-расширения объекта UrlHelper, такой как Url.Action(string actionName, string controllerName). Но этот метод использует нетипизированные параметры, просто имена action и controller, где легко можно ошибиться. А главный недостаток – нет поддержки рефакторинга, и если вы захотите переименовать действие контроллера – вам придется нудно и без гарантий от ошибки переименовывать их вручную.

Но если внимательно посмотреть – то можно найти замечательный класс – ExpressionHelper и его метод GetRouteValuesFromExpression, который по лямбде-выражению (expression) получит необходимые параметры роутинга. Потом, уже на основе этих параметров можно получить и путь. И конечно, с лямбда-выраженями полная поддержка рефакторинга (спасибо ReSharper за наше счастливое настоящее).

Все бы хорошо – но этот метод не принимает во внимание атрибут ActionName, с помощью которого можно изменить имя действия. Встроенная функция всегда возвращает имя метода, которое в 99% совпадает с именем действия, но не всегда.

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

   1: using System;


   2: using System.Linq;


   3: using System.Linq.Expressions;


   4: using System.Web.Mvc;


   5: using System.Web.Routing;


   6:  


   7: using Microsoft.Web.Mvc.Internal;


   8:  


   9: namespace MediaOnline.Web.Helpers


  10: {


  11:     public static class UrlExtensions


  12:     {


  13:         public static string Action<T>(this UrlHelper url, Expression<Action<T>> action) where T : Controller


  14:         {


  15:             return Action(url, null, action);


  16:         }


  17:  


  18:         public static string Action<T>(this UrlHelper url, string name, Expression<Action<T>> action) where T : Controller


  19:         {


  20:             return RouteTable.Routes.GetVirtualPath(url.RequestContext, name,


  21:                 GetRouteValuesFromExpression(action)).VirtualPath;


  22:         }


  23:  


  24:         public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller


  25:         {


  26:             var route = ExpressionHelper.GetRouteValuesFromExpression(action);


  27:  


  28:             var body = (MethodCallExpression)action.Body;


  29:             var customName = (body.Method.GetCustomAttributes(typeof (ActionNameAttribute), false))


  30:                 .Cast<ActionNameAttribute>().FirstOrDefault();


  31:  


  32:             if (customName != null)


  33:             {


  34:                 route["Action"] = customName.Name;


  35:             }


  36:             return route;


  37:         }


  38:     }


  39: }


суббота, 1 ноября 2008 г.

Удаленный импорт в Trac

Даже для маленькой компании (или одного разрботчика) необходимы инструменты для организации работы на проектами. Кроме системы контроля версий исходного кода, необходимость которой сегодня не отрицает никто, очень полезны системы учета ошибок (баг-тракинга) и базы знаний (часто на основе Wiki). Очень удачным воплощением всего этого набора инструментов в одном флаконе является Trac.

В интернете можно найти много сервисов предлагающих хостинг этого набора для вас за деньги или даже бесплатно. Одним из иэтих сервисов я и воспользовался около года назад, http://www.assembla.com. Но тут, совсем недеавно, они взяли и поменяли свои условия предоставления услуг – и теперь бесплатно ими можно воспользоваться только для OpenSource проектов. Я не буду акцентировать внимание на таком поведении (но надеюсь, вы все поняли и не будете пользоваться  их услугами ;) ). Я стал искать альтернативы – и нашел похожий сервис, предлагающий бесплатный Trac для закрытых частных проектов – DevjaVu.

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

Если копнуть глубже – Trac хранит свои данные в локальной базе данных SqLite. Так что я имею к ним доступ на свой локальной машине. Если копнуть еще дальше, то у Trac есть огромное число плагинов и расширений, среди который есть XmlRpcPlugin, который позволяет управлять и изменять данные Trac через протокол XML-RPC.

Теперь дело за малым :) Берем .NET в руки, в виде библиотеки XML-RPC.NET, замечательный ORM инструмент Business Logic Toolkit for .NET скомпилированный с дополнительными библиотеками для доступа к SqLite, и вуаля. Читаем из таблиц локальной БД нужную информацию и заливаем её на Trac через XML-RPC. Если кому интересны детали – могу выложит исходники TracImporter (так я его назвал :) ) в открытый доступ.

P.S. Также, во время реализации, я воспользоваля ещё одной фичей библиотеки BLToolkit – Duck Typing (утиная типизация). Очень удобно.