среда, 8 июня 2011 г.

Разработка Ribbon для SharePoint 2010

При разработке ribbon панелей для SharePoint 2010 столкнулся с тем что они кешируеться, и обновления не происходит. Быстрое решение пришло само собой - нужно изменить GUID фичи, где находиться эта панель. Но быстрое не значит правильное! Оказывается это кешируеться браузером, и его ручная очистка помогает.
Но это также можно сделать и из командной строки:
rundll32.exe inetcpl.cpl, ClearMyTracksByProcess 8
например на PostBuild Event.

среда, 20 апреля 2011 г.

Регистрация своего VirtualPathProvider из Feature activation

Для регистрации своего VirtualPathProvider из Feature activation на понадобиться собственно какая нибудь фича, желательно со scope="WebApplication"
Выглядит это так:

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace QpmWcfSupport
{
    public class FeatureActivation : SPFeatureReceiver
    {
        #region Private Members
        SPWebApplication _chosenWebApp = null;
        #endregion
        #region Implementation Of SPFeatureReceiver
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            Init(properties);
            WcfSupport(true);
        }
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            Init(properties);
            WcfSupport(false);
        }
        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }
        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
        }
        #endregion
        #region Private Methods
        private void Init(SPFeatureReceiverProperties properties)
        {
            SPFeature feature = properties.Feature;
            SPSite siteCollection = properties.Feature.Parent as SPSite;
            if (siteCollection == null)
            {
                SPWeb web = properties.Feature.Parent as SPWeb;
                if (web != null)
                    _chosenWebApp = web.Site.WebApplication;
                else
                    _chosenWebApp = properties.Feature.Parent as SPWebApplication;
            }
            else
                _chosenWebApp = siteCollection.WebApplication;
        }
        private void WcfSupport(bool add)
        {
            ModifcationEntry wcfEntry = GetWCFSupportEntry();
            SPWebConfigModification modification = CreateModification(wcfEntry);
            if (add)
            {
                this._chosenWebApp.WebConfigModifications.Add(modification);
            }
            else
            {
                this._chosenWebApp.WebConfigModifications.Remove(modification);
            }
            this._chosenWebApp.Farm.Services.GetValue().ApplyWebConfigModifications();
            this._chosenWebApp.Update();
        }
        private SPWebConfigModification CreateModification(ModifcationEntry modEntry)
        {
            SPWebConfigModification mod = new SPWebConfigModification(modEntry.Name, modEntry.Path);
            mod.Owner = "MyCompany";
            mod.Sequence = 0;
            mod.Type = modEntry.ModType;
            mod.Value = modEntry.Value;
            return mod;
        }
        private ModifcationEntry GetWCFSupportEntry()
        {
            ModifcationEntry wcfEntry = new ModifcationEntry();
            wcfEntry.Name = "add[@name='WCFSupport']";
            wcfEntry.Path = "configuration/system.web/httpModules";
            wcfEntry.Value = "";
            wcfEntry.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
            return wcfEntry;
        }
        #endregion
    }
}

SharePoint 2007 и WCF

Как захотсить WCF SharePoint 2007? а точнее PSI extesion для ProjectServer2007 на WCF?
Оказалось не сложно, если вкратце, то:

  1. Написать и установить свой VirtualPathProvider для svc
  2. Изменить web.config приложения для регистрации нового VirtualPathProvider 
  3. Правильно разместить сервис
Теперь подробнее:
1. По этому поводу есть куча статей нам понадобиться собственно провайдер и класс регистрации. Это провайдер:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Hosting;
namespace WCFSupport
{
    public class WCFVirtualPathProvider : VirtualPathProvider
    {
        public override string CombineVirtualPaths(string basePath, string relativePath)
        {
            return Previous.CombineVirtualPaths(basePath, relativePath);
        }
        public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
        {
            return Previous.CreateObjRef(requestedType);
        }
        public override bool DirectoryExists(string virtualDir)
        {
            return Previous.DirectoryExists(virtualDir);
        }
        // all other methods omited, they simply call Previous... like the above.
        public override bool FileExists(string virtualPath)
        {
            string fixedVirtualPath = virtualPath;
            if (virtualPath.StartsWith("~") && virtualPath.EndsWith(".svc"))
            {
                fixedVirtualPath = virtualPath.Remove(0, 1);
            }
            return Previous.FileExists(fixedVirtualPath);
        }
        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath,
               System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }
        public override string GetCacheKey(string virtualPath)
        {
            return Previous.GetCacheKey(virtualPath);
        }
        public override VirtualDirectory GetDirectory(string virtualDir)
        {
            return Previous.GetDirectory(virtualDir);
        }
        public override VirtualFile GetFile(string virtualPath)
        {
            return Previous.GetFile(virtualPath);
        }
        public override string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies)
        {
            return Previous.GetFileHash(virtualPath, virtualPathDependencies);
        }
        protected override void Initialize()
        {
            base.Initialize();
        }
    }
}
Это регистратор:
namespace WCFSupport
{
    public class WCFVPPRegModule : IHttpModule
    {
        static bool wcfProviderInitialized = false;
        static object locker = new object();
        public void Init(HttpApplication context)
        {
            if (!wcfProviderInitialized)
            {
                lock (locker)
                {
                    if (!wcfProviderInitialized)
                    {
                        WCFVirtualPathProvider wcfVPP = new WCFVirtualPathProvider();
                        HostingEnvironment.RegisterVirtualPathProvider(wcfVPP);
                        wcfProviderInitialized = true;
                    }
                }
            }
        }
        public void Dispose()
        {
        }
    }
}
2. В web.config (C:\Inetpub\wwwroot\wss\VirtualDirectories\app\web.config) в секцию  добавить сборку, будет что то типа:
     

3. Что бы зацепить SPContext надо разместить в одной из 2-х папок
  • "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\" 
  • "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\" 
Я создал паку в ISAPI: ISAPI\PSI\MyService\"
Туда поместил 2 файла:
MyService.svc:
<%@ Assembly Name="MyService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxx"%>  
<%@ ServiceHost Service="MyService.Service" %>
web.config с параметрами сервиса

пятница, 25 февраля 2011 г.

"Just me", "Everyone" и пользователь SYSTEM

MSI которые генерирует MS VS имеют 2 опции при установке:
  • Everyone
  • Just me
При выборе Everyone, будут созданы ярлыки если они есть в общем профиле, а также есть еще одна особенность:
Custom Actions будут выполнены от пользователя SYSTEM.
А это может быть серьезным ограничение, например если из Custom Actions вы пытаетесь установить wsp для SharePoint или активировать Features, и при этом SQL сервер вынесен на отдельную машину, то SYSTEM не имеет доступа к базе, и дать его невозможно (ну или я не нашел как), а действия фактически пойдут от его имени.

Выхода 2:
  • скрыть опцию Everyone из инсталятора
  • попробовать использовать WIX, там есть флаг имперсонализации

четверг, 24 февраля 2011 г.

Обновление файлов в msi


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

Итак обновление:
  1. Открыть MSI с помощью ORCA
  2. Запомнить Cabinet Id из таблицы MEDIA, это Id cab файла в котором лежат файлы.
  3. В таблице File зпомнить File Id нужно файла
  4. Достать cab файл из MSI: "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\MsiDb.Exe" -d msiName.msi -x "_6B1C2906BF2562A8192CB0382D711877"
  5. Переименовать _6B1C2906BF2562A8192CB0382D711877 в *.cab
  6. Распаковать cab, например с помощью 7z
  7. В качестве имен файлов там используются Id, найти  свой файл и обновить его
  8. Запаковать cab:
    MakeCAB.ddf :
    .OPTION Explicit
    .Set DiskDirectoryTemplate=CDROM
    .Set CompressionType=MSZIP
    .Set UniqueFiles=Off
    .Set Cabinet=On
    .Set MaxDiskSize=CDROM
    ;******************************************
    _21167989434C2FB0A2AAF37341B48FE4
    _22D916C2425750D2242B53C82C13E7A4
    _25E9BCFDE1831D1D2B622AE0ADEEA789
    _274295E7C8E0ECD4FC19D38017ABD787
    "MAKECAB.EXE" /F MakeCab.ddf /D CabinetNameTemplate=data.cab
  9. Переименовать cab в Cabinet Id  ("_6B1C2906BF2562A8192CB0382D711877")
  10. Запаковать это в MSI:
    "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\MsiDb.Exe" -d msiName.msi -k "_6B1C2906BF2562A8192CB0382D711877"
    "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\MsiDb.Exe" -d msiName.msi -a "_6B1C2906BF2562A8192CB0382D711877"
Если создать на все это батники, то будет довольно быстро.
Минусы: размер файлов не обновляется в таблице, но все вроде работает.