Tuesday, July 29, 2014

SharePoint: exclude files from WSP

copyright from: shareddev.blogspot.com

Publishing of WSPs in Visual Studio is very simple and straightforward. But this process includes absolutely everything into WSP (aspx, ascx, css, js, etc), even if we don’t need them. For example, if we have minified versions of javascript files, we definitely don’t need debug versions in production. SharePoint tooling doesn’t really help us when we need to customize building process for our solutions. But luckily we have MsBuild! I’ll come up with simple solution on how it’s possible to exclude some files from Layouts directory. Everything that will be described below has been tested in Visual Studio 2012 and SharePoint 2010.

When we click Publish button from VS menu, it executes the following MSBuild file:

c:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets

A closer look to this file shows that we can officially override two targets here: BeforeLayout and AfterLayout. We need to do two things - exclude file from WSP and exclude it from manifest.xml. Excluding from WSP is simple enough. According to Microsoft.VisualStudio.SharePoint.targets file there is EnumeratedFiles ItemGroup created before BeforeLayout target, so we can exclude some files in this target like that:

12345678
Name="BeforeLayout" Condition="'$(Configuration)'=='Release'">
Files="@(ExcludedFiles)" SourceFiles="@(EnumeratedFiles)">
ItemName="Result" TaskParameter="Result" />
Remove="@(Result)"/>
view rawgistfile1.xml hosted with ❤ by GitHub
ExcludedFiles ItemGroup should be defined earlier. FindInEnumeration is simple task that finds files in MSBuild ItemGroup array. Using MSBuild 4.0 we can use little C# snippets in order to create tasks:

12345678910111213141516171819202122232425262728293031323334353637383940414243
TaskName="FindInEnumeration" TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
Include="System" />
Include="System.Core" />
Include="System.Xml" />
Include="System.Xml.Linq" />
Include="Microsoft.CSharp" />
Namespace="System" />
Namespace="System.Reflection" />
Namespace="System.IO" />
Namespace="System.Linq" />
Namespace="System.Xml.Linq" />
Namespace="System.Net" />
Namespace="Microsoft.Build.Framework" />
Namespace="Microsoft.Build.Utilities" />
 
Type="Fragment" Language="cs">
<![CDATA[
try
{
var filesToFind = Files.Select(item => item.GetMetadata("FullPath")).ToArray();
 
Result = SourceFiles
.Where(file => filesToFind.Contains(file.ItemSpec))
.ToArray();
return true;
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
return false;
}
]]>
After we excluded items from WSP let’s exclude them from manifest.xml. We have to do it separately because manifest files are gathered before BeforeLayout target and we have no control over it. We need to define the following AfterLayout target:

123
Name="AfterLayout" Condition="'$(Configuration)'=='Release'">
Files="@(ExcludedFiles)" ManifestPath="$(ManifestPath)" />
view rawafter-layout.xml hosted with ❤ by GitHub
ExcludeFromManifest task reads manifest.xml file from pkg folder and removes ExcludedFiles items from it:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
TaskName="ExcludeFromManifest" TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
ParameterType="System.String" Required="true" />
ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
Include="System" />
Include="System.Core" />
Include="System.Xml" />
Include="System.Xml.Linq" />
Include="Microsoft.CSharp" />
Namespace="System" />
Namespace="System.Reflection" />
Namespace="System.IO" />
Namespace="System.Linq" />
Namespace="System.Xml.Linq" />
Namespace="System.Net" />
Namespace="Microsoft.Build.Framework" />
Namespace="Microsoft.Build.Utilities" />
 
Type="Fragment" Language="cs">
<![CDATA[
try
{
var excludedFiles = Files.Select(item => item.ItemSpec).ToArray();
 
var manifestPath = ManifestPath.TrimEnd(new[] { '\\' }) + @"\manifest.xml";
var manifestXml = File.ReadAllText(manifestPath);
var manifest = XElement.Parse(manifestXml);
var excludedElements =
manifest.Descendants().Where(element => element.Name.LocalName == "TemplateFile")
.Where(element => excludedFiles.Contains((string) element.Attribute("Location")));
 
excludedElements.Remove();
manifest.Save(manifestPath);
return true;
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
return false;
}
]]>
Please note that I added Condition="'$(Configuration)'=='Release'" condition to both targets, so only Release version of WSP will not contain excluded files, Debug version should stay untouched for development mode of course.

Here is the link to the whole build file:

https://gist.github.com/vadimi/5572446

You can just include it in your project, import it through   and modify ScriptsDir, ManifestPath, ExcludedFiles variables according to your project needs.

Wednesday, July 2, 2014

Hosting Custom WCF Services in IIS vs SharePoint

copyright from: nikpatel.net

Please note that this article refers to Custom WCF Services built to access SharePoint data or extend SharePoint Operations and what items needs to considered while making decision of hosting in IIS or SharePoint environment.
With SharePoint 2010, Microsoft has allowed SharePoint developers an option of hosting Custom WCF Services in SharePoint 2010 environment. Additionally, WCF Services can be hosted in IIS as well. As with many other Microsoft technologies, developers and administrators faces decision making process whether to deploy custom WCF Services in SharePoint or IIS. Unfortunately, I haven’t come across any official guidance in this matter from Microsoft and most of the articles on TechNet or MSDN demonstrate custom WCF service hosted in SharePoint 2010.
In this article, I will try to list high level items needs to consider while making decision on deploying WCF Service in IIS or SharePoint.
Hosting WCF Service in IIS
  • Can be deployed to dedicated IIS web servers, non-SharePoint servers to utilize dedicated RAM
  • WCF Service would run in its own worker process or application pool
  • WCF Service can have separate authentication and authorization mechanism than SharePoint Implementation.
  • WCF Service can be configured with impersonate = false to run WCF Service logic as application pool service account.
  • If you are accessing or processing SharePoint data from WCF services, you must use REST based API or client side object model to integrate with SharePoint implementation unless you are deploying WCF services as dedicated IIS web site on SharePoint Servers.
  • Needs to deploy WCF service on multiple IIS servers with load balancer to provide high availability
  • WCF Service hosted on separate IIS server wouldn’t interfere with SharePoint processes and chew up RAM required by SharePoint operations
Hosting WCF Service in SharePoint
  • Runs in SharePoint Web Application’s worker process
  • Deployed to SharePoint servers in the farm using SharePoint solutions framework
  • WCF Service would have to use same authentication and authorization mechanism as SharePoint Implementation.
  • WCF Service can’t be configured with impersonate = false since impersonation is enabled by default in SharePoint 2010. This allows calling application to run WCF service in user context and return security trimmed data.
  • If you are accessing or processing SharePoint data from WCF services, it provides best performance because it runs under SharePoint worker process and can use Server Side Object Model
  • WCF Service is already deployed to all the WFE servers and provides high availability by using SharePoint inbuilt load balancer
  • WCF Service hosted in SharePoint worker process would share RAM with SharePoint operations and it may degrade SharePoint performance and scalability
  • If your web application is configured with claims based authentication, it is important to remember that IIS website is configured to have anonymous access. Since your WCF endpoints would be hosted in SharePoint web application, it may receive requests from anonymous users. It is always best practice to check if user is authorized user in WCF service implementation.
Based on above items, hosting WCF Services on dedicated IIS servers would make great case for centralized enterprise services library especially when performance, security, scalability, authentication, and authorization model matters most. This would allow hosting all the custom WCF Services in single environment managed by single team whether they are based on SharePoint or not.
Best use case to deploy WCF Service in SharePoint is to extend SharePoint capabilities and run WCF Services in User Context like out of box WCF Services hosted in ISAPI directory (e.g. Client.svc or ListData.svc or ASMX files). Additionally, hosting WCF services would allow you to use Administrative SharePoint APIs which isn’t available in Client Object Model or REST based API. E.g. User Profile Services API are not available through client object model and if your WCF service is maintaining User Profiles, you have to use Server Side Object Model and hosting custom WCF Service in SharePoint would make more sense.
And, here is the Kicker. You can also host WCF Services as dedicated IIS web sites on the SharePoint Servers to use best of both worlds. This would allow performing Administrative SharePoint operations using Server Side Object Model with dedicated worker process, impersonation model, authentication model, and authorization model. Recently I wrote SharePoint Site Provisioning WCF web service which needed to run under farm account (impersonation = false), anonymous authentication disabled, and perform Administrative APIs using Server Side Object Model. This was perfect case where I needed to host WCF services on IIS servers on SharePoint Servers.
Hopefully this article would help making intelligent decisions while hosting custom WCF Service based on SharePoint Framework.