PowerShell: Get version and ProductId from an .app package
In my project I deploy some apps directly through the ObjectModel directly with PowerShell. The apps are built with TFS I have a script that installs or updates apps if there is a new version of the app. Previously I used Import-SPAppPackage to compare the version and productid with an existing app instance, but often I get this error:
The provided App differs from another App with the same version and product ID.
Count lines of code with PowerShell
Today I got a question:
How many lines of code are there in our SharePoint solution?
After a little search, I found that PowerShell is really a nice tool to count lines of code:
I wanted to count lines for different types of code:
- Code Behind written in C#, the files have .cs file extension
- JavaScript code (except jQuery, angular or knockout frameworks)
- PowerShell files (.ps1 and psm1)
- Xml files (all the SharePoint .xml files)
Here is the powershell code that counts lines of code: [code language=“powershell”] # go to the solution folder cd #count lines in .cs files ls -include *.cs -recurse | select-string . | measure | select count #count lines in our .js files ls -include *.js -recurse ` -exclude *min.js, jquery*, _*, jsrender*, CamlBuilder*, knockout* ` | select-string . ` | measure ` | select Count #count lines in our powershell scripts ls -include *.xml -recurse | select-string . | measure | select count #count lines in our powershell scripts ls -include *.ps1, *.psm1 -recurse | select-string . | measure | select count [/code] Just a curious fact, I can’t tell you how many lines of code we have in our solution, but I can reveal the proportions. If I used the flexible box model in css3, it would look like this: There are as many lines of code written in javascript as it is in C#. The main reason that for the big js code base are the SharePoint hosted apps. The PowerShell scripts are as big the javascript code base. Xml files are 4 times bigger than C# code, and it is even bigger than the sum of all lines of code written in C#, JavaScript and PowerShell. It isn’t strange that xml is dominating, almost everything in SharePoint is defined in xml. Fortunately, there are less cases where you have to write raw xml in Visual Studio 2012/2013 and SharePoint 2013. How does it look in your project? What language is dominating in your SharePoint project?
Debugging OOB SharePoint. Unable to post comments on SharePoint blogs (SP2013 June CU)
I have had a strange bug. The comment text box in a OOB SharePoint 2013 blog doesn’t appear. It only says: “There are no comments for this post.” In this blog post I’ll tell you how I found the bug and I’ll show you how you can temporarily bring the commenting to life. I have had luck. While it doesn’t work on the Test Environment, it does actually work on my development machine. The comments text box is rendered as an OnPostRender action in the blog comments display template. After debugging the javascript in hours and comparing the two environments, I just could confirm that displaytemplates are the same. There are two main javascript files that are involved:
Log to ULS using javascript
The more javascript code is produced in SharePoint solutions, the more need we have to log information and possible errors to a central logging place in SharePoint: ULS. This blog post is about logging to ULS from javascript. For a while ago I read a blog post:
The author @avishnyakov mentions the ability log to ULS from javascript. I want to dive deeper. [sourcecode language=“javascript”] ULS.enable = true ULSOnError(“Hello from javascript”, location.href, 0); [/sourcecode] What this function actually does, is that it calls a web service called _vti_bin/diagnostics.asmx
We can follow the function in the init.debug.js [sourcecode language=“javascript”] function ULSOnError(msg, url, line) { return ULSSendExceptionImpl(msg, url, line, ULSOnError.caller); } [/sourcecode] ULSOnError invokes ULSSendExceptionImpl: [sourcecode language=“javascript”] function ULSSendExceptionImpl(msg, url, line, oCaller) { if (Boolean(ULS) && ULS.enable) { ULS.enable = false; window.onerror = ULS.OriginalOnError; ULS.WebServiceNS = “http://schemas.microsoft.com/sharepoint/diagnostics/"; try { ULS.message = msg; if (url.indexOf(’?’) != -1) url = url.substr(0, url.indexOf(’?’)); ULS.file = url.substr(url.lastIndexOf(’/’) + 1); ULS.line = line; ULS.teamName = “”; ULS.originalFile = “”; ULS.callStack = ‘\n’ + ULSGetCallstack(oCaller) + ‘’; ULS.clientInfo = ‘\n’ + ULSGetClientInfo() + ‘’; ULSSendReport(true); } catch (e) { } } if (Boolean(ULS) && Boolean(ULS.OriginalOnError)) return ULS.OriginalOnError(msg, url, String(line)); else return false; } [/sourcecode] ULSSendExceptionImpl invokes ULSSendReport: [sourcecode language=“javascript”] function ULSSendReport(async) { ULS.request = new XMLHttpRequest(); ULS.request.onreadystatechange = ULSHandleWebServiceResponse; ULS.request.open(“POST”, ULSGetWebServiceUrl(), async); ULS.request.setRequestHeader(“Content-Type”, “text/xml; charset=utf-8”); ULS.request.setRequestHeader(“SOAPAction”, ULS.WebServiceNS + “SendClientScriptErrorReport”); ULS.request.send(’’ + ‘<soap:Envelope xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=“http://www.w3.org/2001/XMLSchema" xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/">' + ‘soap:Body’ + ‘’ + ‘’ + ULSEncodeXML(ULS.message) + ‘’ + ‘’ + ULSEncodeXML(ULS.file) + ‘’ + ‘’ + String(ULS.line) + ‘’ + ‘’ + ULSEncodeXML(ULS.callStack) + ‘’ + ‘’ + ULSEncodeXML(ULS.clientInfo) + ‘’ + ‘’ + ULSEncodeXML(ULS.teamName) + ‘’ + ‘’ + ULSEncodeXML(ULS.originalFile) + ‘’ + ‘’ + ‘</soap:Body>’ + ‘</soap:Envelope>’); } [/sourcecode]
scriptcs and SharePoint. How SharePoint can benefit?
Last Saturday I attended Leetspeak. Among many awesome speeches and presentations I discovered scriptcs. scriptcs lets you write C# code directly in the console, or execute scripts written with just your favourite editor. Please see more about it on the site. What I thought during Justin Rusbatch’s session at Leetspeak:
Can we use scriptcs in SharePoint?
Technically there is no limitations in SharePoint for scriptcs. Any .NET code can be registered, imported and invoked in a console or in a standalone script. Here is the simple code for instantiating a site collection and disposing it: [code language=“csharp”] #r Microsoft.SharePoint; using Microsoft.SharePoint; var site = new SPSite(“http://dev”); site.Url site.Dispose(); [/code] The code above does not do anything, it is just there to demonstrate how you can register the SharePoint assembly (“Microsoft.SharePoint”) and import it into the script: [code language=“csharp”] using Microsoft.SharePoint; [/code] The example shows even that you in scriptcs no longer need the necessary “boilerplate” (compared to a console application): namespace, Program, Main()… You can just directly write your code. The rest is the same as in a C# application. The code samples for scriptcs can be any code written in C# for SharePoint, code from custom console applications, from feature receivers, you name it. So my next question is:
Apps can only call the OOB CSOM and REST endpoints
As a SharePoint architect or a SharePoint developer, you must have been thinking about the benefits/limitations of SharePoint apps a lot. I want to point out one of them today, which is very important: using custom webservices deployed to SharePoint inside apps. That is impossible and it is designed to be so due to the security architecture in the sharepoint app framework. I have read much about SharePoint apps (books, whitepapers, blog posts) and stumbled over these two contradictive statements:
javascript: Alert Me on a Page
Recently I needed to add an Alert Me link on Pages. Alert Me is a well known SharePoint functionality for notifying users about changes in list or list items. It is availabe in OOB SharePoint as a command in Ribbon if you go to a list view: When you click on this ribbon command, SharePoint opens a modal dialog and takes you to layouts page: SubNew.aspx. To open a modal dialog and load a page is not a rocket science. So a custom “Alert Me” link is doable. As the first step I copied the html markup from the ribbon and adjusted it a little bit. [sourcecode language=“html”] Alert Me [/sourcecode] Then the javascript code which gets the List ID and Page ID is very simple because this information is there in the magic _spPageContextInfo: [sourcecode language=“javascript”] var takana = window.takana || {}; takana.alertMe = function () { var url = String.format("{0}/{1}/SubNew.aspx?List={2}&ID={3}" , _spPageContextInfo.webAbsoluteUrl , _spPageContextInfo.layoutsUrl , encodeURI(_spPageContextInfo.pageListId) , _spPageContextInfo.pageItemId); OpenPopUpPage(url); } [/sourcecode] This code will open a modal dialog in exactly the same way as the ribbon command in OOB SharePoint and let you subscribe to changes on that page. In this code I use String.format which is available on SharePoint pages and _spPageContextInfo which has existed since SharePoint 2010 and has been extended with more useful information about the current context.
javascript: Remove illegal characters in url
Recently I needed to create valid urls for pages using javascript. Also this time I thought it must be some out-of-the-box code for that in SharePoint. The first thing I came up was the “Add page” dialog. I found that the actual dialog was in the _layouts virtual folder:
/\_layouts/15/CreatePublishingPageDialog.aspx
```Bingo, it does the validation in the client side. This is the responsible javascript function that resides directly in the page: \[sourcecode language="javascript"\] function UpdateUrl() { LoadTermContextInfo(); var hiddenPageUrlLabelExtensionClientId = "<%=hiddenPageUrlLabelExtension.ClientID%>"; var hiddenPageUrlLabelExtension = document.getElementById(hiddenPageUrlLabelExtensionClientId); var pageNamePreviewUrlLabelClientId = "<%=pageNamePreviewUrlLabel.ClientID%>"; var pageNamePreviewUrlLabel = document.getElementById(pageNamePreviewUrlLabelClientId); if( pageNamePreviewUrlLabel != null ) { var nameInputTextBoxClientId = "<%=nameInput.ClientID%>"; var nameInputTextBox = document.getElementById(nameInputTextBoxClientId); var allowSpaces = false; if( GetInnerText(hiddenPageUrlLabelExtension) != "" ) { var suggestUrlValue = ""; for (var i=0; i < nameInputTextBox.value.length; i++) { var currentChar = nameInputTextBox.value.charAt(i); if (IndexOfIllegalCharInUrlLeafName(currentChar) == -1 && !(currentChar == ' ' && allowSpaces == false) && currentChar != '.' && currentChar != '+') { suggestUrlValue += currentChar; } else if (currentChar == ' ' || currentChar == '+' || (currentChar == '.' && i > 0 && i < (nameInputTextBox.value.length - 1))) { suggestUrlValue += '-'; } } UpdatePreviewUrl( suggestUrlValue ); } else { if( g\_timerId != 0 ) { window.clearTimeout(g\_timerId); } g\_timerId = window.setTimeout(OnFriendlyUrlNameChanged, 500); } } } \[/sourcecode\] This function iterates through all the characters in the page url and removes the illegal characters. The space, plus sign and the dot become a hyphen. To determine if a character is illegal, it relies on another javascript function called: `IndexOfIllegalCharInUrlLeafName`. This function can be found in the init.js or init.debug.js: \[sourcecode language="javascript"\] function IndexOfIllegalCharInUrlLeafName(strLeafName) { for (var i = 0; i < strLeafName.length; i++) { var ch = strLeafName.charCodeAt(i); if (strLeafName.charAt(i) == '.' && (i == 0 || i == strLeafName.length - 1)) return i; if (ch < 160 && (strLeafName.charAt(i) == '/' || !LegalUrlChars\[ch\])) return i; } return -1; } \[/sourcecode\] This function checks a char against an array of all characters: `LegalUrlChars` from the same file: init.js. [![ill_002](https://sharepointkunskap.files.wordpress.com/2013/06/ill_002.png)](https://sharepointkunskap.files.wordpress.com/2013/06/ill_002.png) To use this UpdateUrl function, we have to remove the references to the fields from the Add Page Dialog. Of course, we won't overwrite this original function, we don't want to break the SharePoint OOB functionality. Here is how my new function looks like: \[sourcecode language="javascript"\] var takana = {}; function takana.updateUrl(url) { var allowSpaces = false; if( url ) { var suggestUrlValue = ""; var length = url.length; for (var i=0; i < length; i++) { var currentChar = url.charAt(i); if (IndexOfIllegalCharInUrlLeafName(currentChar) == -1 && !(currentChar == ' ' && allowSpaces == false) && currentChar != '.' && currentChar != '+') { suggestUrlValue += currentChar; } else if (currentChar == ' ' || currentChar == '+' || (currentChar == '.' && i > 0 && i < (nameInputTextBox.value.length - 1))) { suggestUrlValue += '-'; } } } } \[/sourcecode\]
#### Server Side
For those of you who want run this operation on the server, here is the code written in C#: \[sourcecode language="csharp"\] //" # % & \* : < > ? \\ / { } ~ | var illegalChars = @"\[""#%&\\\*:\\<\\>\\?\\\\\\/\\{\\}~\\|\]"; pageName = Regex.Replace(pageName, illegalChars, string.Empty); var punctuation = @"\[\\s\\.;\\+\]"; pageName = Regex.Replace(pageName, punctuation, "-"); //remove "--" pageName = Regex.Replace(pageName, @"\\-{2,}", "-"); pageName = string.Format("{0}.aspx", pageName); //do it like the built-in dialog, lower case pageName = pageName.ToLower(); \[/sourcecode\] Don't forget to leave a comment if you find this post useful.
## Comments from Wordpress.com
####
[Johannes Milling](http://discoveringsharepoint.wordpress.com "johannesmilling@hotmail.com") - <time datetime="2013-08-23 09:53:30">Aug 5, 2013</time>
Good post! :)
<hr />
The CDN concept in SharePoint
How many instances of jquery are there in your SharePoint farm? [sourcecode language=“powershell”] Get-SPWebApplication http://dev ` | Select -Expand Sites ` | Select -Expand AllWebs ` | Select -Expand Lists ` | Select -Expand Items ` | ? { $_.Url -match “jquery.*.js” } ` | select Name, Url [/sourcecode] Have you more than two (jquery and jquery-ui), then you have too much. You can save much place and performance by using Content Delivery Network (CDN) links for the resources like javascript, css, fonts and icons. Consider those Content Delivery Networks:
Convert any web app to a SharePoint app
Have you noticed that you can right-click a web application project in Visual Studio and convert it to a provider hosted app? Well why not? Basically your own website and a SharePoint manifest is all what you need for a provider hosted app. This discovery today made me think about all legacy web apps out there that can be converted to SharePoint apps. Traditionally we had to add plain links to external applications or embed them into an IFrame by hardcoding it in an .aspx page or a Page Viewer WebPart. A web application that should be converted to a SharePoint app can be any web app, not only asp.net web site. For a year ago, I had a little nodejs project to try out mongodb and knockout.js: Anvaska which I published as a heroku app: