August 2014 Blog Posts

Outlook Custom Forms

19 August 2014 |

Заметка специфическая, если не интересуетесь разработкой addin-ов под Outlook можно смело дальше не читать.

В Outlook есть такое понятие Custom Forms, с помощью API их можно создавать и помещать в репозиторий FormDescription.PublishForm при этом репозитории могут быть разных типов OlFormRegistry:

olPersonalRegistry: The Form is registered in the user's personal registry and is only accessible to that user.

olFolderRegistry: The Form is registered in a form registry specific to a particular folder, and can only be accessed from that folder.

А теперь внимание функции удалить из репозитория НЕТ, когда такие косяки видишь в исполнении солидной компании вызывает недоумение – либо нужно делать API нормально, либо не делать вообще.

Удалить конечно можно только вот так сразу не догадаешься. Если опубликовано в olPersonalRegistry (Personal Forms Library), то нужно сначала получить CommonViewFolder следующим образом:

var session = application.GetNamespace("MAPI").Session;

foreach (var s in session.Stores.OfType<Outlook.Store>())

{

    var commonViewFolderId = s.PropertyAccessor.BinaryToString(

        s.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x35E60102"));

    var commonViewFolder = session.GetFolderFromID(commonViewFolderId);

    this.RemoveCustomForm(commonViewFolder, messageClass);

}

А затем найти в этой папке скрытые сообщения у которых MessageClass искомой CustomForms и все их удалить, таким вот образом:

private void RemoveCustomForm(Outlook.MAPIFolder folder, string messageClass)

{

    var session = application.GetNamespace("MAPI").Session;

    var oTable = folder.GetTable("", Outlook.OlTableContents.olHiddenItems);

    var name = folder.Name;

    while (!oTable.EndOfTable)

    {

        Outlook.Row nextRow = oTable.GetNextRow();

        if (nextRow == null) continue;

        var msgClass = nextRow["MessageClass"];

        var msgEntryID = nextRow["EntryID"];

        if (msgClass == "IPM.Microsoft.FolderDesign.FormsDescription")

        {

            var m = session.GetItemFromID(msgEntryID);

            var field = m.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x6800001E");

            if (field == messageClass)

                m.Delete();

        }

    }

}

Как видите всё интуитивно понятно ;-)

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

private void RemoveCustomForm(Outlook.MAPIFolder folder, string messageClass)

{

    var session = application.GetNamespace("MAPI").Session;

    var oTable = folder.GetTable("", Outlook.OlTableContents.olHiddenItems);

    var name = folder.Name;

    while (!oTable.EndOfTable)

    {

        Outlook.Row nextRow = oTable.GetNextRow();

        if (nextRow == null) continue;

        var msgClass = nextRow["MessageClass"];

        var msgEntryID = nextRow["EntryID"];

        if (msgClass == messageClass)

        {

            var m = session.GetItemFromID(msgEntryID);

            m.Delete();

        }

    }

}

Какая из этого мораль, работая с динозаврами помните они всё равно вымрут – достаточно ли весомые у вас причины?

CDN In ASP.NET MVC Bundling

03 August 2014 |

Чистого JavaScript-а недостаточно и фактически разработчики используют достаточно большой набор стандартных/одинаковых библиотек. Благодаря кешированию контента браузерами и CDN (Content Delivery Networks) технологии, затраты на загрузку библиотек на клиент можно сделать не сильно болезненными. Идея проста храним все стандартные скрипты файлы в облаке, загружаем один раз а потом любое приложение может ими пользоваться не выполняя повторную загрузку, в статье CDN in ASP.NET MVC bundling описано как все круто (It’s every easy. Hope you like it. Stay tuned for more!!.)

Когда говорят что всё хорошо это значит что вам не хотят говорить что плохо. А что будет если облако перестанет быть доступным – приложение перестанет работать? Облака надежны – ну да, конечно, опять всё хорошо, были случаи падения у Amazon, ввели санкции и всё перестало работать. Минимизировать риск можно используя CdnFallbackExpression об этом уже позаботились “CDNs fail, but your scripts don't have to - fallback from CDN to local jQuery” здорово – всё хорошо. Если на внешнем URL не специально подготовленная чушь, то всё будет работать как надо, но потенциально это проблема не только надежности но и безопасности.

Риски надежности/безопасности минимальны – всё хорошо. Конечно нет… для js файлов вы напишите CdnFallbackExpression, а как написать для css даже если и напишите, все равно будет создан тег <script>, а не <link> и у вас все равно ничего не заработает. Но решение есть Style Bundle Fallback.

Наконец то всё хорошо, вот только вопрос “задача которая решалась того стоит?” и не превратилось ли по ходу разбирательств всё хорошо во всё плохо ;-) Если вы не боитесь атак против вас со стороны владельцев CDN или вы сами владелец это CDN и у вас большое количество новых пользователей по всему миру, то почему бы и нет – а так всё хорошо.