среда, 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 с параметрами сервиса