Monday, April 7, 2014

Assign default value to person field in out of the box list forms

Boy its been more than a year since I last posted. But here's the latest on my learnings...

Have you ever had a need where you are asked if you can default a person field with current logged in user? I am sure a lot of you may have, and many have went the route of InfoPath forms / 3rd party components & many may have written custom JavaScript to achieve it.

I went ahead and wrote a custom jQuery plugin that i plan to use it for this requirement moving forward. Here's the link to the plugin. In order to get it to work do the following

  1. Open your default new item form in edit mode. 
  2. Add a content editor webpart 
  3. Add content using HTML Markup by click on the content editor web part & clicking on the below options
  4.  on the HTML markup editor  add the below mentioned script
<script src="{relativesiteurl}/scripts/framework/jquery-1.10.2.min.js" type="text/javascript"></script><script src="{relativesiteurl}/scripts/framework/jQuery.commonFunctions.js" type="text/javascript"></script>


<script type="text/javascript">

$(document).ready(function () {


$().assignDefaultUserToPeoplePicker({fieldDisplayName: "Submitted by", loginName:"{loginname}"});

});

</script>

Here the
  • {relativesiteurl} is the relative path to your site collection.
  • scripts is a document library where the jQuery plugin and my custom plugin has been uploaded
  • framework is the folder inside the scripts document library that houses the js files
  • {loginname} is the network user name.

If you don't want it to default to a specific user name and would like to default to current logged in user's loginname do the  following

$().assignDefaultUserToPeoplePicker({fieldDisplayName: "Submitted by"});

I have tested the code in both SP2010 and SP2013 and it works as expected. If any of you run into issues feel free to comment here and I will get back to you as soon as i can.

SP 2010 Test - Screenshot

SP 2013 Test - Screenshot

The way this plugin works is by searching the display name that is being passed to the plugin, and assigning the people picker div the login name that is either passed to the plugin or retrieved using client side object model. It would then invoke the checknames action manually to ensure the login name assigned resolved properly and the assignment is seamless to users.

Friday, December 7, 2012

Access Denied when using InfoPath 2010 and REST web services

Have you created an InfoPath form and used REST webservices to retrieve filtered data using rules to modify  the filter parameters and faced issues.

Very recently we had an interesting problem reported in our production environment where one of the InfoPath form hosted for an application serving executives taking page load times of 45 seconds. We immediately started looking into the form to perform root cause analysis; after spending an hour we realized its due the way the form is designed to retrieve data from a list and use "Filter Data" assignment of the default value of the field.

The list items of that list had grown to 900 items and thus was taking a really long time to load the data and then apply filters, we immediately changed the approach to use ListData.svc REST webservice to retrieve only the filtered data based on the logged in user. While the approach worked fine for the users who had admin privileges but we were getting complaints from the executives that the form has stopped working completely.

Further analysis of ULS indicated an interesting log entry which was triggered immediately when the form was trying to modify the REST url to invoke a REST service call.


12/07/2012 17:01:52.71 w3wp.exe (0x0780) 0x1A5C SharePoint Foundation General 8kh7 High Access denied. a1403e1e-1194-4fc4-bbd7-2fcf2a9cd096

It was found that users with read privileges won't be able to make use of the Modify Filter Parameters ruleset and they need an additional permission set "Browse Directories" in order to make this work. 

So we created an additional permission level which is the replica of the "Read" permission level with an extra permission "Browse Directories" permission added to it. The permission level should look like 


Wednesday, July 11, 2012

SharePoint TermSet and Maximum number of items that can be serialized or deserialized in an object graph is '65536'

We have a business requirement that allows the end users to read certain news articles about the company and like them and based on that it increases the like count and also tags the page with a default SharePoint "I like it" tag. This allows the page to come in the activity feed of the end users allowing his / her colleagues to see the news articles that was liked by him / her.

Everything worked fine until one fine day the custom code started breaking and the error that was getting logged in the ULS logs was

Maximum number of items that can be serialized or deserialized in an object graph is '65536' 


We found that the problem is with the default WCF service limits, as the error indicates it can only serialize 65536 objects. Ok, I understand that but why does the code fail and why is it that if I use SharePoint's native functionality "Like It" works just fine? The answer lied in the custom code that was written to trigger of "I Like it".

The line of code that was the culprit of this error was
Term term = taxSession.DefaultKeywordsTermStore.KeywordsTermSet.Terms["I like it"];

Now you will think ok, that looks perfectly fine but why did it raise the error? The reason is in how SharePoint works, as you can see above the code is actually retrieving the term by indexing on the KeywordTermSet collection. The problem with this approach is that server side code will first bring in the entire collection and then index it and retrieve the actual term. This will work fine if your Managed Metadata Store was present in the same SharePoint farm, but if you have a seperate Shared Service Farm which is hosting your Managed Metadata Store and your code lies in a seperate farm then you will definitely see the issue mentioned above.

To overcome the issue the code was changed to

TermCollection termCollection = taxSession.DefaultKeywordsTermStore.KeywordsTermSet.GetTerms("I like it", true);
Term term = termCollection[0];


This uses the built in function call to only retrieve the term and not the entire collection.

Feel free to comment or raise any questions that you may have and I will more than happy to answer them.

Thanks

Monday, July 2, 2012

Event ID: 8311 The root of the certificate chain is not a trusted root authority

So one of our customer's SharePoint portal goes live. Everyone is happy and there are celebrations all around until an error crops up in production environment which had never occurred in any of the 3 environments (developer, integration, QA).

One of the core functionality of the SharePoint Portal; a custom webpart which places an order for certain product is failing inconsistently. The point of failure was the line of code which was submitting an order on the 3rd party web service consumed by our webpart. The stack trace was as follows

System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) at System.Threading.ExecutionContext.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result) at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.ConnectStream.WriteHeaders(Boolean async) --- End of inner exception stack trace --- at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request) at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request) at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) 

After further diving through the event logs and SharePoint ULS  logs we narrowed down to the actual problem as logged in the ULS logs and also in event logs below.





An operation failed because the following certificate has validation errors:\n\nSubject Name: CN={}, OU={}, OU={}, OU={}, O={}\nIssuer Name: CN={} OU={}, O={}, C=US\nThumbprint: {}\n\nErrors:\n\n The root of the certificate chain is not a trusted root authority


Note: I have removed the details of the actual certificate in the above stack trace

This made me to do some research and stumbling upon quite a few blogs; the most interesting one as below 
http://jeroenvanree.wordpress.com/2012/01/16/event-id-8311-the-root-of-the-certificate-chain-is-not-a-trusted-root-authority/

The above blog did explain the issue & the resolution. Which we did follow but the errors were still coming. It was only after further analysis that I realized that the 3rd party webservice consumed by the webpart has a chain of certificates assigned like screenshot on the right. 


While reading Jeroen's blog above I interpret that I need to only upload the Primary root cert and we are taken care of but it is also required for us to upload the entire chain excluding the first one in the chain (in this case webservice cert). 

Once the intermediate cert was uploaded in the Manage Trust store of SharePoint everything worked as a charm with no run time exceptions and nothing logged in Event / ULS logs. 


I decided to write a post on this to make everyone aware that don't just upload the primary root but you will need to upload all the cert in the chain excluding the first one. 


P.S. This would have been very obvious error and easy analysis if all my environments consistently threw System.Net.WebException. I am still to figure out why only certain web front ends are throwing the error while other execute the code without returning run time error but log in the Event Logs.



Monday, September 26, 2011

Display author's photo on a blog site

Ever come across a scenario where you are asked whether can you display photograph of the person who created the blog?

I was and immediately I started my research in analyzing how best to achieve this? My initial gut feel was to modify the XSLT for the blogs but as always I was trying to search if there was an OOB way to do it.

Below are the steps that you need to perform in order for this to work in OOB manner


Step 1: go to blog site

Step 2: go to Posts list

Step 3: List Settings\





















Step 4: Click on "Created By" column, and as you can see from the image above, change the Show field from Name with presence to name with picture. 
and Voila!!! it will be done. 
Something that I forgot to mention is that this will need user's photo to be uploaded on their My Profile. The users can upload their photo using their My Site. 
Hope this is helpful :) 

Friday, September 9, 2011

SharePoint 2010 and Granular security using Active Directory Groups

Recently in one of our document center portal we had a very specific requirement of providing the security to the document based on the region it was applicable. Example: A contract ABC is applicable to North America - USA & Latin America - Mexico. In this situation the document should only be visible to people who belong to those specific country.

Knowing SharePoint there is no OOB way to do it, we could have used audiences but then it requires a identifier attribute in Active Directory which will be used for identifying region and secondly audiences only limit in what is visible / presented to the end user. By that what I mean is that if the document was just presented using Audience Targetting then the document wouldn't have been visible; but if someone knows the URL of document then they could very well be able to view the document.

The solution that we ended up taking is to use workflows for identifying the region to which document belongs (by looking at a mandatory metadata column) and based on that we would assign Active Directory group for the region. The solution works in theory but the question now was how to model the AD groups?

AD groups can be created in 3 different ways but for it to work with SharePoint; it should only be created as Domain Global Security Group or Domain Universal Security Group. Domain Local just doesn't work. Because we had 2 different forests to take care of we ended up creating regional group for each forest.
One for forest ABC and other for DEF.

I wanted to create a blog for the solution as it may help someone with similar needs, please don't hesitate to contact me if any further details are required about the solution. Lastly would like to credit Joel Oleson's blog 
 that helped in designing my solution. 

Thursday, July 14, 2011

Why go OOB!!!

I have been working on SharePoint for quite some while now. I was first introduced to SharePoint in 2007 when the MOSS B2TR had just come out. It was a different experience altogether getting introduced to a new technology because previously i had just worked on ASP.Net and Windows forms. 

Initially it was very difficult to get adapted to the change as my thought process like any developer was to start building components. So any requirement that i used to get for SharePoint fitment I used to start thinking customization. But over a period of time I realized that SharePoint is really powerful in terms of out of the box capabilities. So before thinking customization, as a SharePoint developer / consultant you should always think how can we have this requirement achieved out of the box even if it means solution doesn't meet 100% of the requirements. Now I may sound stupid here, because you may have been starting to think "what use is the solution if it doesn't meet the requirements". You are right in some sense, but not always it is required to meet the customer's requirements 100% because customers always tell requirements based on what they want. They would never think in terms of maintenance of solution, & secondly they don't understand all the capabilities of the product. That's where we need to pitch in and help them understand on why you should go for OOB development & not customization. From my experience I have noticed that most of the time 80% requirements can be met with OOB implementation and 20% with the governance. 

The advantages of going OOB is as follows
1) Low cost implementation
2) Easy upgrade 
3) Easy deployments 

Now with the customers also opting for SharePoint on cloud, it is really helpful to mold your thought process to go as OOB as possible. As deployments in the cloud can be a tedious task & also the cost of the implementations goes up significantly. 

I would really love to hear your comments or if you would like to correct me if am wrong somewhere. 

Thanks