Showing posts with label Custom development. Show all posts
Showing posts with label Custom development. Show all posts

Sunday, August 27, 2017

Community answerring on typical SPFx usage scenarios

Vesa Juvonen asked the community to give some typical examples of business 'applications' that are build as client-side applications, before typical by utilizing ContentEditor or ScriptEditor. And now likely candidates for SharePoint Framework (SPFx) utilization:
Naturally I'm a good community participant / citizen, and answerred with some example scenarios I build myself of behalf of internal business stakeholders...

Wednesday, June 29, 2016

SharePoint Hosted Add-In or Plain Old JavaScript / HTML5 / CSS?

When Microsoft released the SharePoint App-model (meanwhile renamed to Add-In model), it almost instantaneously became the preferred and dominant development approach for SharePoint customization. Now several years later, and the hype is gone, the question arises whether the Add-In model is the right answer for all SharePoint customization scenarios.
I dare to say no. And feel myself strengthened in that opinion by Microsoft’s latest and greatest SharePoint development approach: the SharePoint Framework. Yes, the Add-In model brings a lot of value, but at the expense of additional development, maintenance and runtime (performance) costs. In case you can bring the same functional value via a strict JavaScript + HTML5 + CSS setup, you can avoid these additional costs. Simple deploy the functionality via resource files, upload to a document library, and include them in the runtime SharePoint page context via a ScriptEditor. Much simpler to develop and deploy than a SharePoint hosted Add-In. And not hindered by iFrame boundaries.
Does this mean I see no value at all for the SharePoint-hosted Add-In model? No, there are definitely scenarios. A clear one is that of a software vendor: with an Add-In the vendor has a self-contained package that buyers can install in their SharePoint site. Another example is for a piece of functionality that is reused throughout the site structure, and that needs per usage its own storage in SharePoint. The Add-In model can provision this per Add-In installation in either the hostweb or the appweb.

Thursday, July 3, 2014

Tip - HowTo restore usage of SharePoint tokens in Visual Studio 2013 for webservice entities

I recently setup a new SharePoint 2013 development + demo environment, and a.o. installed the latest and greatest :-) Visual Studio 2013 edition. In a SharePoint 2013 project, I included some RESTful SharePoint services: WCF services, but also (due reuse) the older ASMX webservice version. Within both service variants I aim to use the convenient Visual Studio support for SharePoint design-time replaceable parameters, aka tokens, that will be replaced by Visual Studio at Solution packaging time with their concrete values.
Example of usage in a WCF service:
Service="TNV.VIEW2.Services.ISAPI.TasksWebProxy.TasksRemoteProxy, $SharePoint.Project.AssemblyFullName$"
Example of usage in an ASMX web service:
<%@ WebService Language="C#" Class="TNV.VIEW2.Dashboard.Services.VIEWProcessService, $SharePoint.Project.AssemblyFullName$" %>
However I noticed that after SharePoint solution deployment, the deployed .svc and .asmx files still contain the token instead of the actual assembly fullname.
The explanation is that Visual Studio applies configuration to determine in which Visual Studio project filetypes it must search for and replace the SharePoint tokens. And in its default configuration, Visual Studio 2013 does not include the .svc and .asmx filetypes (but only for the filetypes: xml, aspx, ascx, webpart, dwp, and bdcm). Akward decision if you ask me: WCF REST services are a valid SharePoint architecture option. And although you must doubt the same for .asmx web services, as Visual Studio users we may assume backwards compatibility on the support we receive from this tool.
The disrupted SharePoint development support can easily be restored by augmenting the Visual Studio configuration. You have 2 options here: do it on development system level, so that it applies at build time for all projects that are packaged on the system. Or include the configuration in the individual Visual Studio project(s).
I favor the last: a) this way, it will be effective on EVERY system that opens the Visual Studio project: on the development systems of your peer project members, and more important: on the (e.g. TFS) build server; and b) as for .asmx it is a valid default assumption that this is obsolete technology, it is justifiable that you must explicit and deliberate restore it for that filetype in only those Visual Studio projects in which you still utilize that older technology.
The steps to also include other than the default filetypes for Token replacement are:
  • Open the .csproj file in an editor (in Visual Studio, Notepad(+), …)
  • Locate the line: <SandboxedSolution>False</SandboxedSolution>
    Note that since the project deployes web services, it cannot be a Sandbox solution
  • And after that line, insert the following line: <TokenReplacementFileExtensions>asmx;svc</TokenReplacementFileExtensions>

Saturday, February 4, 2012

Impossible to use custom implementation of public BCS interface IEntityInstanceProvider

SharePoint Business Connectivity Services contains out-of-the-box webparts to visualize external business data. All the standard BCS business data renderers utilize the pattern that data selection is delegated to a data provider control. The 2 controls are associated via consumer/provider connectionpoints. BusinessDataDetailsWebPart is one of them. Its standard usage is for BCS profile pages. However, usage of this webpart on itself is not necessarily limited to that context alone. The webpart is selectable in the webpart gallery, and can be added to arbitrair SharePoint webpart page. The challenge is how to connect it to an external BCS entity. The trivial approach is to do it similar as on profile pages; feed it via the provider BusinessDataItemBuilder. The working of BusinessDataItemBuilder depends on an ‘ID’ querystring parameter. However, when that parameter is included in the url of a page with the 2 BCS webparts on it, SharePoint faults with an error message:
System.NullReferenceException: Object reference not set to an instance of an object.
  at Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapDataSource.OnInit(EventArgs e)

This occurs because PortalSiteMapDataSource also reacts on the presence of ‘ID’ querystring parameter, but assigns another and in this context incorrect meaning to the value. When the ‘ID’ querystring parameter is renamed, the error is prevented. However, then the standard BusinessDataItemBuilder no longer reacts on it.
A proper solution seemed to build a custom provider that relies on another named querystring parameter to retrieve the BCS entity item. The BCS architecture has the promise to support this: it heavily decouples via interfaces from the specific BCS implementation classes. But this appears to be a false promise. Microsoft already points you to that via the warning accompanying the public (!!) interface IEntityInstanceProvider
This class and its members are reserved for internal use and are not intended to be used in your code.
Still, since the interface is public; and also the connectionpoints are public; it sounded safe to expect it must work. But when I added both my own IEntityInstanceProvider implemenation class and a BusinessDataDetailsWebPart on a page; it was not possible to connect them; not in the GUI, and also not explicit in custom code. Via Reflector I reverse engineered the cause, to ultimately end up with the following:
Microsoft.SharePoint.WebPartPages.WebPartPageUserException was unhandled
Message=The connectionpoint BDWP Item on g_1e1e7d15_652d_44cd_bc7d_9026382ff33b is disabled.
Source=Microsoft.SharePoint
StackTrace:
at Microsoft.SharePoint.WebPartPages.SPWebPartManager.CanSPConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer, Boolean throwOnError)

and digging deeper:
if (!providerConnectionPoint.GetEnabled(connectionAgentByInterfaceName))
{
    if (throwOnError)
    {
        throw new WebPartPageUserException(WebPartPageResource.GetString("SPWebPartConnection_DisabledConnectionPoint", new object[] { providerConnectionPoint.ID, provider.ID }));
    }
    return false;
}
public override bool GetEnabled(Control control)
{
    bool flag = false;
    BusinessDataWebPart part = control as BusinessDataWebPart;
    if (part != null)
    {
        try
        {
            return part.CanConnect(true);
        }
        catch
        {
            return false;
        }
    }
    if (control is BusinessDataItemBuilder)
    {
        flag = true;
    }
    return flag;
}

Thus: although at the external front decoupled via interface IEntityInstanceProvider, internally BusinessDataDetailsWebPart demands it's provider to be either a BusinessDataWebPart or BusinessDataItemBuilder webpart!! So much for interface decoupling.
Confine to this internal constraint by inheriting either of these classes is also not possible: BusinessDataItemBuilder is sealed, and BusinessDataWebPart is public abstract, but with 4 internal abstract methods.
BusinessDataDetailsWebPart also allows to explicit connect it in code with a BCS entity. Less elegant as via the connectionpoint, but workable. The standard BusinessDataDetailsWebPart can then still be used to render the external data item; no need to custom build an own one (or ‘copy’).
BusinessDataDetailsWebPart busDetailsWp = wp as BusinessDataDetailsWebPart;
if (busDetailsWp.BdcEntity != null && busDetailsWp.BdcEntity.Equals(entity))
{
    string entityInstanceId = ((IEntityInstanceProvider)this).GetEntityInstanceId();
    busDetailsWp.ItemID = entityInstanceId;
}

Saturday, December 10, 2011

Synchronisation issue with SharePoint FBA claims-based

In a SharePoint 2010 extranet I apply a custom membership provider for Forms-Based Authentication. The provider works like a charm, external users are authenticated when logging on with valid credentials, and denied access otherwise.
However, after functioning smoothly for a while, we suddenly encountered the error below when trying to logon via FBA:
[FaultException`1: The context has expired and can no longer be used. (Exception from HRESULT: 0x80090317)]
Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.ReadResponse(Message response) +1161205
Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst, RequestSecurityTokenResponse& rstr) +73
Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst) +36
Microsoft.SharePoint.SPSecurityContext.SecurityTokenForContext(Uri context, Boolean bearerToken, SecurityToken onBehalfOf, SecurityToken actAs, SecurityToken delegateTo) +26060225
Microsoft.SharePoint.SPSecurityContext.SecurityTokenForFormsAuthentication(Uri context, String membershipProviderName, String roleProviderName, String username, String password) +26063596
Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage.GetSecurityToken(Login formsSignInControl) +188
Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage.AuthenticateEventHandler(Object sender, AuthenticateEventArgs formAuthenticateEvent) +123
System.Web.UI.WebControls.Login.AttemptLogin() +152
Logon via Windows authentication had no problem, only the FBA route. Since there had been no software or configuration changes for the custom provider, the cause must be found to be at [SharePoint Farm] infra level. In the Application Eventlog I noticed the following Error log: An exception occurred when trying to issue security token: The context has expired and can no longer be used. (Exception from HRESULT: 0x80090317).
This steered me within the direction of the generic Security Token handling in the farm, instead of the context of the extranet webapplication self. As first attempt I decided to restart the SecureToken Service Application. And voila, this was already sufficient: problem resolved. That is, for a while... The problem namely structural reappears after a couple of days of minor or no activity in the SharePoint farm. It looks to me as something of a clock timer synchronization issue within the SharePoint farm, that can for a period be prevented by timely 'refreshing' the SecureToken application pool.

Saturday, November 19, 2011

Alternative ways to programmatic read contents of External List with filtered view

In order to export the displayed contents of a BCS External List to Excel (see previous post), I first have to programmatically retrieve the contents in custom code. The External List has a filter applied to it's Finder method, set via the default SPView:
My first thought was therefore that below code should retrieve the same filtered external data as when rendering the BCS External List on a SharePoint page:
However, GetItems returns an empty collection. Upon debugging the called GetNotifications webservice method, I discovered that the filter-param always has value ‘null’. To me unclear why, since it has been set in the DefaultView.
However, although this approach works; it left me rather dissatisfied. Conceptually I want to export the contents of the same (External) List that I already have provisioned on a SharePoint page; so why should I have to dive under the BCS hood to get the same contents? Also, this code is very much aware / coupled to BCS API, while the 'Export SPList to Excel' functionality on itself is general. Thus, with some ample time available, I decided to analyze the way in which the standard XsltViewWebPart is issuing the external data retrieval – using JetBrains DotPeek reflector tool (as .NET Reflector is no longer free of licensee charge). It appears that this is done slightly different as my original attempt:
Not only is the code LOC of this far less, but also this code is general; applicable for both regular SharePoint lists as BCS External Lists.

Friday, November 18, 2011

Excel 2010 Protected View hinders browser-opening of downloaded .xlsx file

An user requirement in one of our SharePoint 2010 projects is to export at any moment the displayed contents of an External List (with content originating from SAP ERP, retrieved via SharePoint BCS connecting to BAPI based web services) to an offline file. The functional rationale is version-administration for history and auditing purposes. The SharePoint platform supports this out-of-the-box for regular Lists, by the Export into Excel functionality. However, not so for BCS External Lists. But you can realize it yourself via some custom code. First retrieve the External List contents, and next construct a .xlsx file via Open XML SDK. The .xlsx file is generated server-side in memory, and send to the browser as HttpResponse content. The end-user can next either open the file, or save it somewhere at client-side:
Strange thing I noticed was that when saving the file, that saved file can next be opened successfully. But when instead choose to directly open the file, Excel 2010 displays the error message “The file is corrupt and cannot be opened”.
This must be a client-side issue; the server-side is not aware of the context in which the client-side handles the received HttpResponse (Note: via Fiddler I even analyzed that the HttpResponse contents were identical).

The resolution is hinted at in the File Download window, by the trust-warning about internet downloaded files. The default Excel 2010 TrustSettings are to distrust all downloaded content from non-trusted locations. To validate this I unchecked in Excel 2010 the default settings (via File \ Options \ TrustCenter \ TrustCenter Settings \ Protected View):
This helps, Excel 2010 now direct opens the downloaded file.

Friday, November 4, 2011

Programatically open SPSite using Windows Credentials

In a Proof of Concept I employ a SPListMembershipProvider for forms-based access into (sub)sites. For the PoC, a SPList in the rootweb is utilized as User Administration. In SharePoint 2010 architecture, Claims-Based authentication is handled by SecureToken service application. In the local development image, the STS service application may run under the same Application Pool account as the SharePoint webapplication. But this is not recommended, thus not to be expected within a real farm setup. As result, it is not possible to directly access from within runtime STS context the list in the external SPSite.
SPSecurity.RunWithElevatedPrivileges cannot help here; that only be used within the same application pool context. Instead the proper way is to open the SPSite in the external SPWebApplication via the credentials of a SPUser in that site; e.g. that of a service account. Problem is that the SharePoint API does not directly provide a way to open a SPSite with Windows Credentials. You can open a site under the credentials of a SharePoint user, but you need the SPUserToken of the user for this. And guess what, you can only determine that token when within the context of the site. Talking about a chicken-egg situation.
However I came up with a manner to get out of this loop. It consists of a 2-steps approach: first programmatically impersonate under the credentials of the service account, open the site, determine the SPUserToken of the site’s SystemAccount, and undo the impersonation; second apply the SPUserToken to (re)open the site under the authorization of the site’s SystemAccount. Since Windows Impersonation is a resource intensive operation, cache the SPUserToken in memory so that the impersonation is only initially required within the process lifetime.

internal static SPUserToken SystemTokenOfSite(Guid siteId)
{
    string account, pw, domain;
    RetrieveCredentialsFromSecureStore(<AppId>, out domain, out account, out pw);

    ImpersonationHelper _impersonator = new ImpersonationHelper(account, domain, pw);
    try {
        _impersonator.Impersonate();

        SPSite initialAccessIntoSite = new SPSite(siteId);
        return initialAccessIntoSite.SystemAccount.UserToken;
    } finally {
        _impersonator.Undo();
    }
}

...
if (sysToken == null)
{
    sysToken = SecurityUtils.SystemTokenOfSite(memberSitesToId[websiteIdent]);
}

SPSite site = new SPSite(memberSitesToId[websiteIdent], sysToken);

Friday, October 7, 2011

Read content of uploaded file within ItemAdding method

In an application it is required to validate the file content before allowing the upload into a document library. SharePoint 2010 enables this via the ItemAdding synchronous SPItemEventReceiver method. Problem is however that you cannot access the uploaded file through the SPItemEventProperties.ListItem object. The item is at runtime of ItemAdding not yet created in and thus not available via the list. Via blogpost Getting file content from the ItemAdding method of SPItemEventReceiver I found a code-snippet how to access the file. Last remaining issue was that I received empty result upon reading from the filestream. Debugging I discovered that the Stream position was set to the end of file. Which is logical since the file has been read in order to save it to the content database. By resetting the position I can read the file contents, validate it, and cancel the upload in case of invalid content
public override void ItemAdding(SPItemEventProperties properties)
{
  string searchForFileName = Path.GetFileName(properties.BeforeUrl);
  HttpFileCollection collection = _context.Request.Files;
  for (int i = 0; i < collection.Count; i++)
  {
    HttpPostedFile postedFile = collection[i];
    if (searchForFileName.Equals(
      Path.GetFileName(postedFile.FileName), StringComparison.OrdinalIgnoreCase))
    {
      Stream fileStream = postedFile.InputStream;
      fileStream.Position = 0;
      byte[] fileContents = new byte[postedFile.ContentLength];
      fileStream.Read(fileContents, 0, postedFile.ContentLength);
      ...

Friday, June 3, 2011

Utilizing Maps services for runtime determining nearest relations

In a former SharePoint project – an external facing public website -, a required functionality was to display the nearest X insurance advisors given the submitted postal code of user. We weighed several alternatives to realize this:
  1. Re-use the distance-calculation algorithm used by the predecessor of the website (note: the essence of the project was a technical migration from a non-strategic proprietary WCM platform to the enterprise architecture target platform: SharePoint)
  2. Utilize service of postal company: a data repository of all postal code tuple combinations, with the distance between them administrated.
  3. Utilize Geo-coordinates to runtime calculate the distance between 2 locations, via the Haversine formula.
The first would have the disadvantage to still depend on the non-strategic platform and supplier. Also it had a rather complex programming API, without documentation and support.
The second would require us to host an external database besides the SharePoint content database in which to administrate the millions of postal code / distance records. This database would have to be updated each year with the management update from the postal company. Also, security constraints would not allow to directly access from the SharePoint WFE in the DMZ, the external database hosted in the internal network. The access should be regulated from DMZ to inner network via a secure webservice interface; which of course implies extra work and additional hosting costs.
So, the third alternative appeared the best fitted. Issue here is how to translate the postal code (submitted by the website user) into geo-coordinates (required for the Haversine formula). Luckily, both GoogleMaps and BingMaps provide services for this. Rough outline of the applied approach:
    Preparation
  1. Store in a SharePoint List the relations (less than 5000) data, including their geo-coordinates

  2. Runtime
  3. Invoke Maps service to derive the geo-coordinates (Latitude + Longitude) given the postal code submitted by user
  4. Calculate the distance to each applicable relation via the Haversine formula
  5. Ascending sort on calculated distance
  6. Display the X nearest advisors
An hosting constraint for step 2 is that it is not allowed to directly invoke from the SharePoint farm, external webservices. To circumvent that restriction we decided to call the Maps service in the security context of the browser, via jQuery/JSON. The returned geo-coordinated are next via a postback with arguments transmitted to the server side; where then the distance calculations are done.
Architecture sketch:

Thursday, December 23, 2010

SAP Connector for Microsoft .NET 3.0 released

Yesterday SAP made the renewed version 3.0 of the SAP Connector for Microsoft .NET (NCo) officially available. This version is the long awaited successor of NCo 2.0 - which still had a design-time and runtime dependency on .NET Framework 1.x and Visual Studio 2003.
With the NCo, it is possible to directly interoperate from a .NET consumer context with SAP RFC's. It is thus a different approach as with Duet Enterprise - in which the SAP/SharePoint interoperability is achieved via standards-based webservices. The Duet Enterprise services are provided by the SCL, which transparently encapsulates and shields the specifics of the SAP backend towards the SharePoint consuming side.
In the earlier versions the NCo used the SAP librfc32.dll to achieve the SAP/.NET binary interoperability. In NCo 3.0 the RFC protocol is fully re-implemented in the NCo itself. Main advantage is that there is no longer the dependency on the librfc32.dll being available on each .NET consuming system. Also this should result in better performance as there is no more marshalling required in .NET client runtime context from the managed .NET code to the unmanaged librfc32 invocation.
In the previous NCo versions the programming model was to generate at design-time .NET-based proxies in Visual Studio 2003 per SAP RFC that you intend to call. This involved a proxy method for the ABAP Function Module, and an individual proxy class for each structure or data table used in the RFC signature. In case of a change in the SAP backend, the implication is that it is required to regenarate the proxies, and rebuild plus deploy a new assembly for the re-generated code. In NCo 3.0, the RFC call pipeline is dynamically constructed. Whenever there is a change in the enclosed SAP back-end, the NCo on-the-fly adapts the internal RFC invocation. NCo 3.0 transparently shields the .NET consumer from modifications and upgrades in the SAP backend. However, this approach also has its downside. You are in effect developing against a weakly-typed integration API, much resembling the .NET reflection pattern. There is no compile-time validation nor protection for incorrect RFC invocations.
The NCo 3.0 can be downloaded from SAP Service Marketplace, including accompanying documentation.

Wednesday, June 30, 2010

SAP announces a new release of the SAP .NET Connector

In 2003 SAP released the SAP .NET Connector (NCo) to enable communication between the .NET platform and SAP systems. The first NCo versions (1.0x, 2.0) were aimed at .NET 1.x (with support for Visual Studio .NET and later on VS 2003), and it remained at that level. This resulted in the overall conclusion that the NCo was considered 'dead', or at least strongly outdated (Future Support of NCo). This idea was re-enfored in May 2009 by 1) the advice of Juergen Daiberl to use webservices or WCF Lob Adapter in favor of NCo, and 2) a statement of SAP's Rima Rudnik-Sirich phrasing that 'ES Explorer is a successor of NCo'.
However, the truth (or weakness) of SAP Enterprise Services is that currently only a limited set is available, supporting a restricted subset of the SAP business processes functionality. There are alternatives to custom develop SAP/MS intergration whenever it is not standard provided: WCF on SAP webservices, WCF BizTalk Adapter on SAP BAPIs and RFC. And forthcoming is Duet Enterprise, with a positioning for interoperability and collaboration between SharePoint 2010 and Office 2010 clients towards SAP processes and data.
And now SAP apparently decided to give new life to the NCo proposition. They have announced .NET Connector 3.0, to be released in December 2010. At first, this appears strange when you combine this announcement with the upcoming release of Duet Enterprise. However, Duet Enterprise is thus strictly scoped for interoperability between SharePoint plus Office 2010 and SAP environments. A renewed NCo will provide an additional alternative to communicate from other .NET application formats (e.g. WPF, WF, Services) to the SAP systems.

Wednesday, March 31, 2010

Efficient batch deletion from SharePoint List without filling up the site RecycleBin

For a data management function I need a performant way to first delete all items from a SharePoint list, before re-filling it with up-to-date content. Looping through the list and delete each item one-by-one is not acceptable. It would instantiate an internal SPRequest object for each single listitem deletion, and take a longer time to complete. The answer to do it time-efficient is to use the SPWeb method ProcessBatchData(). You feed this method with a batch string of multiple delete commands to perform in a single SharePoint request.
However, usage of ProcessBatchData has the disadvantage that all deleted items are put in the SharePoint SPSite Recycle Bin. Kinda ridiculous for a programmatic batch-based deletion. And because of the larger number of deleted items (the reason for doing the deletion batch-based...), it makes the Recycle Bin pretty much unworkable thus useless for UI initiated restore of manual deleted content items.
SharePoint does not provide an elegant way to prevent this standard behaviour. Elsewhere on the web it is suggested to temporarily disable the Recycle Bin at SPWebApplication level. This however suffers from 2 drawbacks:
  1. The current user needs to have the SPFarm administrator role. This is unlikely for a functional management role, and unacceptable from a security viewpoint.
  2. Disabling the Recycle Bin at webapplication level has a nasty side-effect. It namely clears all Recycle Bins in the webapplication. Not only that of your current context site and sitecollection, but all of them in the webapplication. This effectively destroys the Recycle Bin backup-purpose for manual deleted items; and it is thus not isolated to your scope but affects the entire webapplication. This is functional unacceptable.
So if it's not possible to prevent the batch deleted items from appearing in the Recycle Bin, it is then required to delete them there afterwards. This could be done via a call to SPContext.Current.Web.RecycleBin.DeleteAll(). But this clears the entire Recycle Bin, still potential removing too much. What we need is an approach to delete exactly those items from the Recycle Bin that were put there as result of the list batch-deletion. The Recycle Bin has a different API interface as regular SharePoint lists. Usage of ProcessBatchData to delete the same relevant items from the Recycle Bin is not possible. But it is undesirable to first clear the SharePoint list via a batch-deletion, and next be forced to loop-based remove the same items from the Recycle Bin. Luckily the SPRecycleBinItemCollection class exposes its own method to issue a batch deletion: SPRecycleBinItemCollection.Delete(GUID[]). It has a different method signature, which requires you to first determine the GUID per SPRecycleBinItem. Also you must take care of keeping the chunck of deletion below a thresshold. SharePoint namely locks the database tables when executing the Recycle Bin batch deletion, which hangs the SharePoint server upon deleting a larger set. The Recycle Bin cleanup/reset can be done asynchronous in the background, doing it chunk based.
The code for efficient batch deletion all items of a list, and next clear the same deleted items from the Recycle Bin is as follows:

1. Control for time-efficient purge all items from SharePoint List

2. Cleanup the Recycle Bin in the background

Friday, January 29, 2010

SharePoint [2010] as development, composition + application platform

I consider SharePoint having 2 distinct faces:
  1. It's in itself an application, with lot's of end-user oriented functionality. This is true for the foundation WSS, and significant more for the licensed version MOSS 2007
  2. It's a rich development and runtime application platform, to host your own custom developed applications.
Being primarily development-oriented, it will be clear that personally I like SharePoint best for the second role.
I'm not alone on this. More and more custom company-internal applications are based on and within the SharePoint platform. SharePoint comes out-of-the-box with a well-filled toolbox of both technical as functional building blocks. Developing custom SharePoint applications is therefore a combination of composing and customizing OOTB SharePoint building blocks, and augmenting it with custom developed functionality in which the SharePoint platform does not standard delivers. This implies a significant mindset switch for [old-school] application developers. Instead of the default decision to custom build all application parts, the SharePoint best-practice approach is to first consider the OOTB building blocks. Can you deliver the custom-requested functionality on sufficient level via the application of the standard SharePoint blocks? If so, choose that path. This composition-based approach will gain you in the initial application development stage. But even more it will be cost-benificial within the application maintenance period. It's better to have Microsoft fix and improve on standard building blocks, than have to do it yourself on your own proprietary ones. Of course, this principle can especially be applied on the more technical functionalities. And this gives you more time and relative budget to focus on the differential functionality for your company.
David Chappell has written a conceptual white paper highlighting the application platform aspects of the forthcoming SharePoint 2010. You can download it on the Microsoft site, SharePoint 2010: Developer Platform White Paper.

Thursday, June 25, 2009

Some of my Best Practices in SharePoint development

I've been a 'traditional' developer long before getting into SharePoint. Started on Unix platforms with C, C++ and Objective-C, next Java on both Solaris and Windows, and since 2000 mainly Microsoft (web)development. A common red line during my professional history is to apply Application Lifecycle Management principles. Ok, back then it was not phrased like that...; but still, we applied versioning control, nightly builds, peer reviews, static analysis.
The tooling support for ALM has substantially improved the last years; within Microsoft development most significant available via Team System / Team Foundation Server. Its different aspects - version control, static analysis, build support, work items, reporting, ... - can give a project and its stakeholders a better control and insight on how the project is [non]progressing.

My utmost best practice is to apply these same ALM principles and practices also within SharePoint development projects. This is not always commonplace, due to the different nature of SharePoint development compared to 'traditional' apps. SharePoint is namely amongst others a template platform, with a lot of functional and technical building blocks out-of-the-box available. You typically apply these for your own dedicated SharePoint portal or application via customatization. These are not directly source code artefacts which you edit and version control in a development environment, but can directly be performed in the SharePoint environment itself; and the customizations stored in the SharePoint content database.

That is all fine, excepts it presents you with a challenge when you need to deploy your SharePoint custom application to other environments.
I'm therefore a strong upholder to threat everything the project does for realizing a custom SharePoint application, as a first class source artefact. Store all your intermediate building items within your team productivity environment, and be able to repeatedly produce and provision your SharePoint application on whatever physical server or farm.

This results in my following list of some best practices:
  1. Apply development and ALM principles - structure the application within architecture layers with the different responsibilities, provision the Visual Studio solution structure accordingly, implement and schedule an automatic build, identify, plan and divide the total work within workitems,
  2. Strive for a first fully automatic deployable version as soon as possible. This is key to get your customers and users involved from the early stages on: give them something to see, feel, try-out, critize; but ultimately to reach a common agreement on what to build
  3. Utilize the SharePoint platform's own inherent functionalities within the deployment process - Solution Framework, Features, SPWebConfigModification, ...
  4. Honor the inherent out-of-the-box available SharePoint functionalities, above implementing your own custom variation. This richness is one of the strengths of SharePoint as an application development platform.
  5. From start on [re]consider memory management and performance - for instance, include the usage of SPDisposeCheck within your development and QA processes
  6. Distinguish between the two types of users of a Content Management site: content editors and the end users (readers)
  7. Co-operate with your IT operations staff
  8. Favor FieldControls above using the Content Editor WebPart

I can easily extend this list with more of my own experienced best practices, but then I'll be getting more into technical details and peculiarities. I'll leave that for another blog.