Tuesday, July 26, 2011

Personalization approach / settings administrated outside content database

Personalization is an important functional aspect in my current SharePoint 2010 project. Personalization on itself is a phrase that can have multiple meanings and appearances. Examples:
  • Customize a page for your own preferences; via personal settings of webpart properties
  • Content targeting; on basis of the visitors profile
SharePoint enables page personalization via the Provider model, inherited from ASP.net. Implication of the standard SharePoint personalization approach is that each authenticated user gets an own copy per personalized page in the content database. The personalized settings are thus administrated in the content database, similar as in case of shared webpart properties. A disadvantage of this approach is that this makes it very difficult to (web content) manage the page. A content manager can update the (template) page, but none of the content changes are automatically propagated to the individual personalization page copies in the content database.
In our application scenario, we have the additional functional requirement that it must be viable to extract management information reports of the personalized settings: what type of user (profiles) typically select personalized setting X, choose to close webpart Y etcetera. Although not impossible, it is rather impractical to extract this management information when the personalized data is stored in the content database. The schema of the SharePoint content database must be treated as internal black box, and cannot be relied on. The schema also does not support ad-hoc querying for answering varying management info requests.
We also have User Experience related requirements: the users must be able to personalize, without being aware or be directly confronted with SharePoint. It should be intuitive and natural, without explicit [noticable] personalization-setting modus. Examples of requested personalizations are tuning the webpart behavior via settings, and dynamically reposition the webparts in the page.
These combined end-user and management requirements effectively rank out the utilization of standard SharePoint personalization. So what’s a viable alternative? The one we came up consists of the following elements:
  1. [Standard] shared webpart properties for enabling the content managers to set the initial and default values for personalizable settings. The shared value is regularly stored in the SharePoint content database, and applied for each visitor which has not [yet] explicitly personalized the shared setting.
  2. Storage of personalization settings in an own SQL Server database
  3. The iGoogle-like reposition behavior via jQuery and webpart zones tagged as droppable zones
  4. An abstract base PersonalizationWebPart; that handles both the server-side aspects of personalization (retrieving + applying personalization settings, as well as saving them), as the client-side (webpart movement); and that implements virtual methods for concrete subclasses to hook into.
  5. Custom AudienceProvider to derive on-the-fly whether visitor is within a certain audience by checking setting stored in the own SQL Server database [thus no need for User Profiles, nor compiling of Audiences]
Extra and a major advantage of this personalization approach is that there no longer originates a copy of the page being personalized. If the content manager updates the page, by adding or removing a webpart, modifying content on a publishing page; these changes are automatic and immediate effective for all the visitors, whether one has personalized the page or not.

Wednesday, July 13, 2011

Make AudienceFilter webpart setting visible without User Profile Service Application started

In current project we aim to apply SharePoint's audiencing mechanisme for content targetting. As audience filters we'll use SharePoint group membership, we will not derive the audience from User Profile properties. In our current state of SharePoint farm, the User Profile service application is even not available .
One of the advantages of SharePoint audiencing is that it is out-of-the-box available for every webpart; standard SharePoint and custom webparts. However, when we intended to apply an audience filter to a standard ContentEditorWebPart in our test-environment, we were confronted with a missing Audiencing setting in the webpart toolpart. Search on the web points to prerequiste of the User Profile service application being activated. However, this is neither possible in our farm infrastructure planning, nor needed for the manner in which our application will use audiencing, that is on basis of SPGroup memberships.
Via reverse engineering SharePoint code [using .NET Reflector] I found out what directly determines the visiblity of the AudienceFilter webpart property. The responsible AdvancedToolpart class does a check on the web.config for config property "SharePoint/RuntimeFilter": if the property is not present, or the referred assembly is not valid, none of the webparts in this SharePoint webapplication will display the AudienceFilter webpart property in their toolpart. I validated this by outcommenting in web.config the property; for instance the toolpart of a ContentEditorWebPart then misses the AudienceFilter setting. After reinstating the web.config property, and reopening the toolpart; the webpart property is visible again. And thus available for usage for filters on basis of SharePoint groups, or a custom AudienceProvider.

Friday, July 8, 2011

IBM WebSphere MQ WCF Channel has problem with clustered Queues

The Enterprise Architecture roadmap of customer aims at a SAP-unless policy, and SharePoint for all web-applications/front-ends. Currently there are still multiple applications in their IT landscape which do not obey do this future direction. For some of them, e.g. J2EE based service application, the enterprise architecture integration guidelines prescribes that the client-services communication occurs via IBM WebSphere MQ (WMQ). From the .NET client perspective, WCF based communication is nowadays preferred and proven technology, and must be applied for any new web-applications that invoke other applications.
For .NET client context there are in reality 2 viable WCF Channel options for putting requests as messages on an IBM WebSphere Queue (WCF WMQ). One is part of Microsoft Host Integration Server, the other one is provided by IBM.
For reasons explained else, the.NET and Integration architects decided to apply the IBM WebSphere MQ Channel for WCF. It is successful applied in several .NET applications to put messages on WMQ. In my current application project we also need to invoke services of a ‘legacy’ system, callable over WMQ. However, when this application puts a message on the assigned Queue via Request-Reply, we ran into the following exception:
System.ServiceModel.EndpointNotFoundException was unhandled by user code
Message=WCFCH0309E: An error occurred while attempting to open the channel for endpoint 'jms:/queue?destination=APPL.REQ.QUEUE@XXXX01&connectionFactory=connectQueueManager(XXXX01)clientChannel(WMQ.Channel.TST)clientConnection(dev-xx.xxx.com(7201))&initialContextFactory=com.ibm.mq.jms.Nojndi&persistence=1&replyDestination=APPL.RPL.QUEUE' The operation could not be completed. The endpoint may be down, unavailable, or unreachable, review the linked exception for further details.
Source=mscorlib
StackTrace:
Server stack trace:
at IBM.XMS.WCF.XmsChannelHelper.ThrowCommsException(OperationType op, Exception innerException, String endpointURI)
at IBM.XMS.WCF.XmsChannelHelper.CheckExceptionAndTimeout(OperationType op, Exception e, String timeout, String endpointURI)
at IBM.XMS.WCF.XmsRequestChannel.OnEndOpen(IAsyncResult result)
at IBM.XMS.WCF.XmsRequestChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
at System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Request(Message message, TimeSpan timeout)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at System.ServiceModel.Channels.IRequestChannel.Request(Message message)
at Application.<CustomCode>.Client.<InvocateAMethod>(MethodRequest_1_0 request)
at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
InnerException: IBM.XMS.IllegalStateException
Message=Failed to open MQ queue APPL.REQ.QUEUE. XMS attempted to perform an MQOPEN, but WebSphere MQ reported an error. Use the linked exception to determine the cause of this error. Check that the specified queue and queue manager are defined correctly.
Source=IBM.XMS.Client.WMQ
ErrorCode=XMSWMQ2008
It took me several hours and diverse try-outs together with an MQ developer at the receiving WebSphere MQ side, to ultimately find out the following. The IBM WCF transport channel for WMQ (WebSphere MQ 7.0.1 installation) has a problem with clustered queues, and errors when attempting to open the queue. In case of putting messages to a non-clustered queue – the WMQ infrastructure of the other .NET applications -, the channel opens successfully and messages request + replies are delivered. The problem is reproduced outside the context of our SharePoint application, via a simple testprogram; thus appears to be structural. We are currently addressing IBM to analyze it, and come up with a structural solution. For now, the pragmatic solution appears to communicate via non-clustered Queue.

Tuesday, July 5, 2011

Using ServiceLocator in Sandbox requires pre-generated xml-serialization

The SharePoint Guidance [SPG] ServiceLocator provides you with a ready-to-use implementation of a Dependency Injection container. However, be aware of the following restriction when applying the SPG ServiceLocator in a constrained Sandbox context: it is not possible to compile on-the-fly generated xml-serialization classes, which are required for administrating the service interface and implementation within the servicelocator typemappings.
The execution of code statement:
typeMappings.RegisterTypeMapping<IServiceContract, ServiceImplementation>();
resulted in the following exception inside ServiceLocator code:
Microsoft.Practices.SharePoint.Common.Configuration.
ConfigurationException: Error on serializing configuration data ---> Microsoft.SharePoint.UserCode.SPUserCodeSolutionProxiedException: Error on serializing configuration data ---> Microsoft.SharePoint.UserCode.SPUserCodeSolutionProxiedException: Cannot execute a program. The command being executed was "C:\Windows\Microsoft.NET\Framework64\v2.0.50727\csc.exe" /noconfig /fullpaths @"C:\Users\SPadministrator\AppData\Local\Temp\OICE_925B8D58-F6D1-4BB3-9E01-FCBB9D816D0B.0\wkdrltlt.cmdline".

Explanation of this behavior:

SPG ServiceLocator applies XML serialization to administer the typemappings for the service interface and service implementation class. .NET XML serialization approach supports JIT compilation of the required xml-serialization classes. The benefit is that you do not need to generate and deploy these xml-serialization classes, the XmlSerializer framework generates them on spot. However, to be able to do this assembly generation; the .NET compiler is needed. And when within the Sandboxed constraints, you are not allowed to use filesystem resources.
By doing a little ‘digging’ in the SPG runtime pipeline, I discovered that not even my own custom classes caused the runtime serialization error; it actually could be derived back to the following serialization:
new System.Xml.Serialization.XmlSerializer(typeof(
Microsoft.Practices.SharePoint.Common.ServiceLocation.ServiceLocationConfigData))
The solution is to make sure that the required xml-serialization classes are already available: either in the GAC for generic use, or also deployed in the sandbox. I opted in this particular case to deploy Microsoft.Practices.SharePoint.Common.XmlSerialization.dll in the Sandbox.