In this post, I’ll be building on my SPUploader module to show you how to upload documents while setting the metadata all in a single call. You will need all the code in the first post to make this work.

Uploading Documents

Our goal is to upload a document to a library and set its metadata at the same time using the put document RPC method. There are some additional complications with Office docs that I won’t be addressing, but this should get you started for most file types.

Document Details

The document parameter is where you will specify the document name and all meta data. For a document named SomeStuff.csv with a title of “Some Stuff” to be uploaded in the Stuff folder of our Junk library the document parameter needs to look like this:

The first function, documentDetailString(lines 96-98), will help generate the basic structure of the document parameter’s value. It uses the EncodeString function from my last post to escape both the file name and all the metadata information between the brackets. When we use this later in an RPCParameter object you’ll see that we disable additional encoding since RPC is really finicky about this stuff.

The metadata information for a file is generated using the propertiesToString function (lines 100-124) and expects your metadata to be in a dictionary object where the internal column name is the key (string) and the value is the value (object). We loop through each property and build a strange looking string that indicates which column we are setting, the type of the value (and what action we want performed), and the value itself.

Generally, every property key needs to be set to the internal name of the column (not the display name). However, the Title column is a special case. When you specify Title it actually needs to be vti_title. This is taken care of in lines 105-106.

The meta_info string for each property has two parts separated by semicolons. The first is the internal name of the column, the second is information about the value. This second part also has two parts separated by a pipe. The first part will be two characters. The first character indicates the type of the value (S for everything but Boolean values where you will use B). The second character will always be W(write) and specifies the action to take.

We take care of this with a simple case statement that checks the type of the value (line 110). When it’s a Boolean, we use a B for the type character and set the value to the string true or false (lines 111-113). When it’s a DateTime, we still use S for the type character but we format the value into the standard Sortable format and slap a Z on the end (lines 114-115). For everything else, we specify S for type and use our escapeVectorCharacters method to escape it properly (lines 116-117).

Once we’ve looped through all the properties, we remove the final semicolon (line 123).

The UploadToSharePoint function takes a web URL (this does not have to be the root site in a site collection), the name of the library to upload into, the folderpath (only the immediate directory will be created if needed, if you need to create a full path of directories or ensure they are there, use the CreateFolder function demonstrated in the previous post), the filename (great time to use that UniqueFileName function!), the filebytes, a property dictionary (string, object), the SharePoint version, and some optional parameters (credentials, keepcheckedout, version comments).

If the property dictionary doesn’t contain a Title property, we automatically add one using the filename without the extension (lines 136-138). Now it’s time to create the method parameters.

The first parameter for the put document method is the document parameter (line 141) which we create using the documentDetailString function. Notice that we don’t just specify the filename, but rather the exact path (library + folderpath + filename). We also disable string encoding in the RPCParameter object since this parameter requires very specific encoding that is handled in our helper function.

The second parameter, put_option, is where we specify some combination of the following three strings separated by commas:

overwrite: overwrites existing files with the same filename

createdir: creates the parent directory (does not create a full path)

migrationsemantics: preserves the author, editor and creation information (requires administrative permissions or it is ignored)

For our purposes we are specifying all three (line 142).

The third parameter, comment, is a comment to include for the given version of the file (line 143).

The final parameter, keep_checked_out, takes a string of “true” or “false” (line 144). When true, the document is checked in then checked right back out. When false, the document is just checked in.

To upload the document we must specify all of the method parameters first. We generate the appropriate bytes using our CommandBytes function (line 148). We then have to add the actual file bytes (line 150) but these need to be separated from the command bytes with a line feed (line 149).

That’s it! Now you can upload documents while setting the metadata all in a single call!

Applies To: SharePoint, VB.NET

SharePoint provides many ways to create directories and to upload documents. One of the oldest, and possibly least understood, ways is to use the SharePoint Foundation RPC Protocol.

Generally, using RPC can be more trouble than it’s worth. However, RPC performs and scales well. It supports uploading your content and setting the metadata in one call. You can also use streams rather than just byte arrays. There are a few other reasons why you might choose RPC over the more common solutions, but I’ll assume you know what you’re trying to accomplish.

In this post I’ll give you some basics about executing RPC methods and demonstrate by showing you how to create multiple directories in a single call.

Getting Started with RPC

The most frustrating part of working with RPC can be trying to track down working examples. In addition, the documentation is pretty sparse. It can also be difficult to find out exactly how you should be encoding your commands and exactly which part(s) should be encoded. Ultimately, you are just making an HTTP POST, but figuring out the correct payload can take a lot of trial and error. Especially since RPC is a little light on helpful error messages.

I’ve broken things down into several utility functions that should help keep things relatively simple and eliminate a lot of the low level troubleshooting that can slow you down.

I’m using VB.NET because the project I initially integrated these calls into was written in VB.NET. Nearly every example I saw out there was in C# and it shouldn’t be too hard to translate my code as needed. Should you have any difficulty, just leave a comment below. I have also placed all of my code inside a Module named SPUploader for convenience.

Above are just a couple of simple functions that help to prepare strings. The characters that need to be escaped and the way in which certain parts are encoded can be difficult to sort through in RPC. We’ll be using these both quite a bit.

The EncodeString function uses the standard UrlEncode method with one additional encoding for periods. Some RPC methods don’t seem to have a problem with periods, but they all work with encoded ones. The escapeVectorCharacters function escapes the following characters \;|[]=

RPC Method Helpers

RPC methods are called using the method name, exact SharePoint version, service name and then any parameters. For instance, the create url-directories method that we will be using to create directories should be called like this:

This presents a few challenges. First, we need the exact version of SharePoint before we make any calls. Hardcoding this is just asking for trouble. Second, what is the service_name? (Hint: It generally doesn’t matter and can almost always be left as /) and finally what are the parameters and how should those be included?

We’ll get to the specifics of the create url-directories method, but first let’s look at a series of functions that simplify how we call RPC methods in general:

Public Function SharePointVersion(sharepointURL As String) As String
Using client As New WebClient()
client.UseDefaultCredentials = True
client.DownloadString(sharepointURL)
Return client.ResponseHeaders("MicrosoftSharePointTeamServices")
End Using
End Function

I adapted the above function from Joshua on Stackoverflow. This is a quick call to SharePoint that will give you that exact version string needed in all RPC methods. The general idea is that you can call this before an RPC method and cache the result for additional calls.

Here’s a helper method that takes care of building the properly encoded method string:

This function simplifies generating the method:server_extension_version portion of the command.

Helper Class: RPCParameter

When dealing with additional parameters for methods (anything beyond method and service_name), the encoding of those parameters can get a little tricky. I’ve written a helper class called RPCParameter that can help smooth this trickiness:

In general, parameters come exactly as you’d expect with a key=encodedvalue. However, there are some variations that can complicate things. This object may seem a little strange but it will become more obvious when we actually see it used. By default, a simple RPCParameter object is just a Key Value Pair with a custom ToString override that outputs key=encodedvalue.

There are some additional properties, however, that can customize this behavior. You can turn off encoding for the value by specifying the Encode property as false. The IsMultiValue property will insert the square brackets before encoding the value. This is important because often the values need to be encoded, but not the brackets.

Generating the Command

Every RPC method is just a string of parameters (Command String) that we convert to a byte array to upload as part of an HTTP POST. Here are a series of overloaded functions to help generate that command string into a byte array:

Public Function CommandBytes(method As String, SPVersion As String, parameter As RPCParameter, Optional serviceName As String = "/") As Byte()
Return Encoding.UTF8.GetBytes(CommandString(method, SPVersion, parameter, serviceName))
End Function
Public Function CommandBytes(method As String, SPVersion As String, parameters As List(Of RPCParameter), Optional serviceName As String = "/") As Byte()
Return Encoding.UTF8.GetBytes(CommandString(method, SPVersion, parameters, serviceName))
End Function
Public Function CommandString(method As String, SPVersion As String, parameter As RPCParameter, Optional serviceName As String = "/") As String
Dim parameters As New List(Of RPCParameter)
parameters.Add(parameter)
Return CommandString(method, SPVersion, parameters, serviceName)
End Function
Public Function CommandString(method As String, SPVersion As String, parameters As List(Of RPCParameter), Optional serviceName As String = "/") As String
Dim command As New StringBuilder
command.AppendFormat("method={0}&service_name={1}", methodValue(method, SPVersion), EncodeString(serviceName))
For Each parameter As RPCParameter In parameters
If parameter.IsValid Then
command.AppendFormat("&{0}", parameter.ToString)
End If
Next
Return command.ToString
End Function

The CommandBytes functions (lines 27-33) encode the result string into a byte array and allow you to specify either a single RPCParameter object or a List of RPCParameter objects.

The CommandString fuctions actually build the string (lines 35-50). The only difference between them is that if you specify a single parameter, it gets converted to a List of parameters.

The real work for all 4 of these functions occurs in the final CommandString function (lines 41-50). We build the initial method=method&service_name=/ string that is used for every RPC method (line 43). Notice that we use our methodValue helper function to simplify things and and we always encode the service_name value.

Finally, we loop through the RPCParameter objects and append them if they have keys (IsValid) using the RPCParameter.ToString call that takes into account our individual encoding preferences.

So now that we can build the Command String, how do we actually send it to the server?

Executing an RPC Method

Executing an RPC method is really just sending an HTTP POST to a specific dll using the Command String as the payload. This can be easily done using a WebClient object:

The ExecuteRPC function creates a WebClient object and sets the Content, X-Vermeer-Content-Type, and user-agent headers (lines 56-59). The main action happens in line 60 when we call the UploadData method causing the POST to the author.dll (there are additional dlls that can be used depending on your method, but this was the only one I’ve needed so I left it this way for simplicity) using the byte array we generate from the CommandString functions.

So far all we’ve done is setup all the helper functions so that we can call generic RPC methods. Any confusion on how we take advantage of all this code should clear up once we look at actually executing a real method.

Creating Directories

Our goal is to create a directory (or more often, multiple directories) using the create url-directories RPC method. We want to be able to take a folder path and ensure every folder in that path exists or is created. For instance, given the folder path “Some Folder/Sub Folder 1/Some Other Folder” we need to potentially create 3 directories in a single RPC method call.

The create url-directories method has only one parameter: urldirs. This parameter is an array of directories, along with properties for each, that we would like created if they don’t already exist. For our purposes, we’re just going to create standard folders without specifying any additional properties. Here’s what the code looks like:

The CreateFolder function takes a web URL (this does not have to be the root site in a site collection), the name of the library in which to create the folder(s), the folderpath, the SharePoint version, and optionally the credentials to be used during the call (if not specified, the default credentials are used).

If the folderPath isn’t a blank string (line 67), then we strip off any trailing forward slashes (line 68). We then call our ExecuteRPC function using the bytes generated by calling the CommandBytes function using the method create url-directories.

In our ExecuteRPC function call we pass a single RPCParameter object. This is the urldirs parameter and we specify that it is a MultiValue parameter (this will ensure we have the required square brackets around the value). We set the value of the RPCParameter to the result of the folderPathToURLDirectories function. Finally we return the result from the server.

The folderPathToURLDirectories function is used to build our urldirs parameter. Directories need to be created in the proper order (parents first) and each need to have their full path (including the libraryName) in the form [url=path;meta_info=[]]. So if we have the path “Some Folder/Sub Folder 1/Some Other Folder” for the library Documents we want to end up with:

We do this by splitting the folderPath (line 85) and tracking the parent (including the libraryName) as we create each entry (lines 86-91).

That’s it! Now we can create a bunch of directories in SharePoint using the RPC Protocol! WOWEE! Stay tuned for my next post where we will add to our code to allow us to upload documents and set metadata all within a single call!

Applies To: Construct 2, CefSharp, VB.NET, WinForms, jsMessage

In my previous post, Embedded Chromium in WinForms, I walked you through creating a simple WinForms application that will load local html resources into an embedded Chromium browser using CefSharp. This article will build on that application to show you how to host Construct 2 games inside your WinForms application. Additionally, I will show you how to use my Construct 2 jsMessage plugin to communicate directly from .NET code to your running game.

You can also just use your own game or one of the many sample games that comes with Construct 2. However, you won’t be able to follow along with the Sending/Receiving messages section of this post without the jsMessage plugin.

Building the Game

In the Export Options dialog choose the location as a C2 folder inside your application’s directory (mine is bin/x64/debug/C2). Youalso need to uncheck the Minify script checkbox. I’m unsure of the reason but currently you will receive an error in the console if you attempt to load a game that has been minified using C2. I suspect this is an issue with the version of Construct 2 I am running but it could easily be CefSharp. Either way, uncheck the box for now and click Next:

Choose Normal Style in the template options and click Export.

Loading the Game

Assuming you are using the same WinForms project created in my Embedded Chromium in WinForms post you can just switch the address in the browser constructor to local://C2/index.html

Go ahead and run the application. If the game shows up for you, fantastic!

Unfortunately, I get a blank screen when using the default settings. I’m able to fix this by disabling the GPU hardware acceleration. This is a known issue with certain versions of Chromium when paired with specific drivers/hardware. If you have this issue, you can easily pass Chromium Command Line Switches using the CefSettings object in CefSharp. We can do this by adding this line right before we call the Cef.Initialize function in our Form constructor:

settings.CefCommandLineArgs.Add("disable-gpu","1")

When you run the application it should look similar to the following:

This “game” doesn’t have much to offer without some additional plumbing (see below) but it is fully interactive. If you were to switch it out for a platformer game or something similar you would see that all the key presses, clicks, etc. are all passed just like you’d expect!

Sending Messages to Construct 2

The jsMessageTest Basic game was built with the jsMessage plugin. This plugin allows the game to respond to jQuery events and to trigger events of its own. You can find a lot more detail about how this works with this game in my post, jsMessage Basic Example.

It’s really pretty straightforward if you’re familiar with jQuery events so we won’t be spending much time on explaining it. Suffice it to say we are going to be injecting JavaScript in to our browser that will allow us to interact directly with the game from the code.

I’ve added a GroupBox labeled Send Messages and inside I’ve put a TextBox called txtMessageToSend and a Button called btnSendMessage. Here’s the code for the btnSendMessageClick EventHandler and the helper sub SendMessage:

Private Sub btnSendMessage_Click(sender As Object, e As EventArgs) Handles btnSendMessage.Click
If Not String.IsNullOrEmpty(txtMessageToSend.Text) Then
SendMessage(txtMessageToSend.Text)
txtMessageToSend.Text = String.Empty
End If
End Sub
Private Sub SendMessage(Message As String)
If browser IsNot Nothing Then
addActivity(String.Format("MESSAGE: {0}", Message))
browser.ExecuteScriptAsync(String.Format("$(document).trigger('CKjsMessageSend','{0}');", Message))
End If
End Sub

In the Click EventHandler (lines 49-54) we’re just making sure there is a message to send, calling the SendMessage sub and clearing the txtMessageToSend box.

The SendMessage sub is doing the actual interesting work. First, we verify the browser is setup. Then we use our addActivity sub to log the message. Finally, we call the ExecuteScriptAsync method which allows us to execute JavaScript directly on the page within our browser. This JavaScript triggers the CKjsMessageSend event with our message as the parameter (this is the format expected by the jsMessage plugin).

Run the application, type something in the box and click Send and you should have something like the following:

Receiving Messages from Construct 2

Construct 2 can send messages via jQuery events using the jsMessage plugin. We can easily register a JavaScript function to be performed when that event is triggered. But how do we respond to that with .NET code?

CefSharp provides the ability to expose a .NET class to JavaScript. This is totally awesome. There are some limitations regarding the complexity of the objects and their return types, etc. all of which you can find on their project page. For our purposes, we just need a simple proxy object that can accept messages and route them.

Add another class to your project called MessageReceiver.vb and copy/paste the following code into it:

This is not particularly exciting code but it should illustrate what is possible. It should also look somewhat familiar if you followed the steps to make our LogDialogHandler object in the last article. In our constructor (lines 5-7) we accept an Action(Of String) which we will use to handle our logging. We store this Action into our private logReceiver object (line 6) so that we can use it later.

There is just one method, log, which takes a string, adds “RECEIVED:” to the front of it and calls the logReceiver action. I’ve lowercased this method to match what will happen once exposed to JavaScript. CefSharp automatically changes methods and properties into JavaScript-casing (the first letter is downcased). I find it less confusing to just do that directly in the object.

Now we just need to register our object into our browser. We can do this once the browser is initialized using the RegisterJsObject method. Here is the line of code to do that in the Form constructor right after setting up our JsDialogHandler:

The RegisterJsObject takes 2 parameters: The name we want to use in JavaScript for the object and the object itself. In our case we want it called messageReceiver (this will be a global object) and we just create a new instance of our MessageReceiver pointing the logReceiver Action to our addActivity method.

Go ahead and run the project and click the DevTools button. Switch to the console and start to type messageReceiver. You’ll find that Chrome’s autocomplete recognizes that there is a global messageReceiver object. If you call the messageReceiver.log function with a string you’ll see it show up in the Activity feed:

Now we just need to tell jQuery to call this function when receiving a message from the Construct 2 game. We do this by using the ExecuteScriptAsync method we used earlier when sending messages.

However, we have to make sure the game is loaded before we insert the event handler or it won’t take effect. We can do this by taking advantage of the browser’s IsLoadingChanged event. Add the following line to your Form constructor right after our RegisterJsObject call:

Private Sub onBrowserIsLoadingChanged(sender As Object, e As CefSharp.IsLoadingChangedEventArgs)
If e.IsLoading = False Then
browser.ExecuteScriptAsync("$(document).on('CKjsMessageReceive',function(e,m){messageReceiver.log(m);});")
RemoveHandler browser.IsLoadingChanged, AddressOf onBrowserIsLoadingChanged
End If
End Sub

The IsLoadingChanged event provides us with a helpful event argument that tells us if the Browser is loading or not. We verify that it is no longer loading then inject our JS event handler and remove the .NET event handler from the IsLoadingChanged event (since we only need to call this once).

Run the application and type a message in the game textbox and click the jsMessage plugin icon (the turquoise speech bubble) and you’ll see that message come into the Activity feed:

You now have all the basic plumbing in place to host a Construct 2 game directly in your WinForms application and to be able to send and receive messages directly from the game! This opens up a wide range of possible applications. I wrote all of this for an integrated project I’m working on, but I hope you find it helpful too!

Applies To: WinForms, VB.NET, CefSharp

Getting Chromium to show up inside a .NET WinForms application is relatively easy using CefSharp. CefSharp is an open source project which provides Embedded Chromium for .NET (WPF & WinForms). It’s a great way to get Chrome hosted inside of your .NET application.

You can get a simple browser up and running in 5 minutes – which I’ll show you first. There are some additional steps required to use local resources and to handle console messages and dialog prompts which I’ll also show you.

Embedding a Chromium Browser

There’s an easy example over on the CefSharp project page called the MinimalExample that will get you up and running quickly with a bunch of the basics. I’m going to walk you through some very quick steps to just get an embedded browser working in a WinForm.

Getting CefSharp

First, create a new WinForms project. I’m using VB.NET (but C# works great too, of course) and am targeting .NET 4.5. Once you’ve got a project, you’ll need to add the CefSharp binaries. This is done through NuGet and is really simple.

In Visual Studio choose PROJECT > Manage NuGet Packages… In the Package Manager window switch to Online and search for CefSharp. You’ll select CefSharp.WinForms(My version is 37.0.0 but the package should always have the latest stable release) and choose Install:

This will take just a few seconds while it also adds all of the dependent packages. In the end you’ll have 4 packages (CefSharp.WinForms, CefSharp.Common, cef.redist.x64 and cef.redist.x86).

Initial Build

CefSharp doesn’t support the default AnyCPU build configuration. You’ll need to choose BUILD > Configuration Manager… Then change the Active solution platform to either x64 or x86(just choose new and it’ll walk you through it). Here’s what my Debug configuration looks like:

Go ahead and build the project to make sure there are no reference errors.

Adding the Browser

Open your form and slap a Panel control on there (I’ve named mine panBrowser and set it’s Dock property to Fill). This isn’t required, but it certainly makes it easier to move around when changing your form later.

Switch to the Form’s code and go to the New sub (Constructor in C#). Here’s the code:

Be sure to make the appropriate references above (lines 1-2). In this code, we have a ChromiumWebBrowser object (line 6) that we create with a default address and a dock style of Fill (lines 14-15). We then add that control to the Panel we added above. The only other thing we need to do is to call the Cef.Initialize function (line 12). We’re just passing default settings for now (line 11). Run it and you should see something similar to this:

Congratulations, you’ve got Chrome in your Form!

Loading From Local Resources

In a previous article, Use Local Files in CefSharp, I showed you how to make the necessary objects to register a CefCustomScheme that would load resources from the local file system. I also posted a similar article, Use Embedded Resources in CefSharp, to demonstrate how to load files directly from your project’s manifest. Those articles will give you more detail about how to do this. If you’re following along in C# just head over to that article and copy the objects. Otherwise, here they are in VB.NET:

LocalSchemeHandler

Add a new Class to your project called LocalSchemeHandler.vb and copy/paste the following:

LocalSchemeHandlerFactory

Add another new Class to your project called LocalSchemeHandlerFactory.vb and copy/paste the following:

Imports CefSharp
Public Class LocalSchemeHandlerFactory
Implements ISchemeHandlerFactory
Public Function Create() As ISchemeHandler Implements ISchemeHandlerFactory.Create
Return New LocalSchemeHandler
End Function
Public Shared ReadOnly Property SchemeName() As String
Get
Return "local"
End Get
End Property
End Class

Registering the Scheme

To tell the browser to use the LocalSchemeHandler we just need to adjust our settings object before the Cef.Initalize function from our Form constructor above:

Proving it Works

To make sure everything is working we’ll need to have an actual local resource to load. Open your application’s directory (mine is bin/x64/debug) and create a folder called web. Cut and paste the following into a text file and save it as index.html in that web folder:

Create an images folder inside the web folder and save this image as truck.png in there:

None of these files need to be added to your project, they just need to be in the directory with your executable. Now if you switch the address from the browser initialization code above to local://web/index.html and run the project you should see something like this:

Mapping the Console

You might have noticed a <script> tag in our index.html above with a call to the console. CefSharp provides us with an easy event, ConsoleMessage, that allows us to grab those messages and do whatever we want with them. In our case we just want to display those messages in a TextBox.

I’ve added a Groupbox below the panBrowser Panel control from earlier and put a TextBox control called txtActivity inside it. I’ve set the txtActivity properties like so: Dock=Fill, Multiline=True and ScrollBars=Both. Now we just need to add the following code to our Form code right after the constructor:

We’ve added a handler for the ConsoleMessage event (lines 25-31). The ConsoleMessageEventArgs object provides us with three useful properties: Message, Source and Line. We always receive the Message and depending on how the call to the console was made we may receive information about the Source. When the Line is greater than 0 we output the Message and the Source/Line information, otherwise it’s just the Message.

We’ve also added a helper sub, addActivity, to take care of handling displaying the output. This allows us to easily change our handling in the future but it also simplifies thread considerations. Our embedded browser is multithreaded and the ConsoleMessage event generally doesn’t fire on the main thread. This is the reason for the InvokeRequired/Invoke code in lines 34-36. The actual display happens in line 37 where we use the AppendText method to ensure our textbox scrolls appropriately. Run the project and should see something similar to this:

Handling Dialogs

What about dialog messages? If you uncomment the alert command from the index.html above and run the application you’ll see that in WinForms this gets automatically handled with a MsgBox:

In our application we’d like to redirect these to our Activity feed as well. In CefSharp, you override the default handling of dialogs (alerts, confirmations and prompts) by implementing an IJsDialogHandler object.

In our case we just want everything noted in the activity feed and ignored. To do this, add a class to your project called LogDialogHandler.vb and copy/paste the following code into it:

The IJsDialogHandler interface requires us to implement the OnJSAlert, OnJSConfirm and OnJSPrompt functions. We’ve also added a construtor that takes an Action(Of String) which we will use to handle our logging. We store this Action into our private logReceiver object (line 8) so that we can use it later. Then in our implementation of the functions we just call logReceiver with an informative message regarding what’s occurred. In each case we return True to indicate that the alert, etc. has been handled.

To use our new object we just add the following line to the end of our Form constructor:

This allows us to direct any message from our LogDialogHandler to our txtActivity box just like our console messages. Now when we run the application we should see something like this:

DevTools

Anyone that’s used Chrome for web development is very familiar with the F-12 DevTools and knows they can be invaluable in tracking down issues. Wouldn’t it be nice to have those when working within your .NET application? With CefSharp, it’s super easy. I’ve added a simple button underneath my Activity GroupBox called btnDevTools. Here’s the Click EventHandler:

That’s it! Now when you push the button you get the full power of the Chrome DevTools all while running in your form:

Conclusion

Obviously, there is a lot you can do with this and there are many features we haven’t even begun to demonstrate, but this should get you started. For me the goal has been to get a Construct 2 game running in a .NET application. In my next post I’ll show you exactly that.

Applies To: SharePoint, SQL, .NET, HTML5

I just got back from DevConnections 2012 in Las Vegas, Nevada. I learned several things that the made the trip worthwhile and I’m glad I got to be a part of it. I choose DevConnections over SPC because I wanted to take workshops from a variety of tracks including SQL, .NET and HTML5. Choosing DevConnections also meant I didn’t have to go alone.

There were several good speakers and I received plenty of swag (8+ T-Shirts, an RC helicopter, a book and more). Not surprisingly, I enjoyed the SharePoint Connections track the most and Dan Holme was my favorite speaker.

For all those that didn’t get to go I thought I’d share my notes from the sessions I attended and any insights I gained as well. My notes are not a total reflection of what was said, but represent things I found interesting or useful.

Where Does SharePoint Designer 2010 fit in to Your SharePoint Application Development Process?

Formulas: select parameter and double click the function to have the selection become the 1st parameter

DVWP can easily be changed to do updates: switch from text to text box, then add a row and insert a form action button and choose the commit action (save)

Parameters for all sorts of stuff (username, query string, etc)can be used all over including in conditional formatting

SPD was designed and intended to be used in production – not a lot of support for working in Dev and moving to Production

WP can be packaged (DVWP) for import elsewhere

Reusable workflows can also be packaged

Key Insights:

SharePoint Designer is fine to be used in production (and in fact requires it in certain cases). However, there are things you can do to minimize the amount of work done in production.

SP Designer is pretty powerful and can replace a lot of extra VS development

Overall Impression:

Just as in his videos, Asif was a great presenter. He was very personable and knowledgeable. The session ended up being less about when SP Designer should be used in your environment and more a broad demo of what can be done with Designer. This was a little disappointing but I learned enough tips and tricks that I really didn’t mind too much. Interestingly, some people in the audience asked about an intermittent error they’ve been receiving in SP 2010 for some Web Parts they’d applied conditional formatting too. This was almost certainly the XSLT Timeout issue and I was able to provide them a solution.

Key Insights:

Silverlight has lost to HTML 5 and we shouldn’t expect another version.

Overall Impression:

This was obviously a recycled workshop from several years ago (he actually said so) that he added a couple of slides to. In his defense, he planned to show a WinRT demo but the Bellagio AV guys were unable to get the display working. Regardless it seemed more like a bragging session. He showed pictures of him with top Microsoft people, showed his company being featured in Gray’s Anatomy, and alluded to all the cool things he’s involved with that he couldn’t mention.

This was pretty disappointing. I am already aware that .NET can do some pretty awesome things including some neat visualizations. I was hoping to get some actual guidance on getting started. Instead I got Microsoft propaganda from 3 years ago about why .NET (specifically WPF) is awesome. Tim Huckaby is obviously a very smart guy and has a lot of insight to share. Hopefully I’ll be able to attend a workshop from him in the future on a topic he cares a little more about.

OOTB \14\TEMPLATE\LAYOUT\Ratings.js: ExecuteDelayUntilScriptLoaded(RatingsManagerLoader, ‘ratings.js’); RatingsManagerLoader is huge, see slides. Then loop through everything you want to attach a rating to.

AppParts are really just iframes. Connections work different. Not designed to communicate outside of app.

Key Insights:

Silverlight to Silverlight communication is pretty simple but will be pretty irrelevant in SharePoint 2013

Getting the Video Player to show your videos when using custom XSLT takes some work

Adding a working Ratings Control when using custom XSLT is even more complicated and convoluted

New GeoLocation columns in SP 2013 will be really cool, but adding them to existing lists is going to be a pain.

Overall Impression:

Todd had a lot of good information and you could tell he knew his stuff. Unfortunately he has a very dry style. Regardless, I enjoy demos that show actual architecture and code and there was plenty of that.

I do wish he’d updated his demos to use HTML 5 as he recommends. It’s very frustrating to hear a presenter recommend something different and then to spend an hour diving into the non-recommended solution. Additionally, although I prefer specific examples (and his were very good) I prefer to have more general best practices/recommendations presented as well. But despite all that he gave a few key tips that I will be using immediately and that is the primary thing I’m looking for in a technical workshop.

Getting Smarter about .NET

My Notes:

int + int will still be an int even if larger than an int can be. No errors, but addition will be wrong. (default in C#, VB.NET will break for default)

There is no performance gain by using int16 over int32, some memory is saved but is only significant when processing multimillion values at the same time

VisualStudio 2012 will be going to quarterly updates

Static values are shared with all instances – Even among derived classes!

LINQ queries Count() does full query

Func last parameter is what is returned

Closure is the actual variable in a lambda (not copy) so multiple lambdas can be changing the same variable

Projects can be opened in both VS 2010 and VS 2012 at the same time

Key Insights:

Despite all the new and exciting things that keep getting added to .NET, a firm grip of the basics is what will really make a difference in your code and ability to make great applications

Static sharing even among derived classes makes for some potential mistakes, but also for some very powerful architecture

LINQ and Lambdas are some crazy cool stuff that I should stop ignoring

.NET is very consistent and following it’s logic rather than our own assumptions is key for truly understanding what your code is doing

Overall Impression:

I really enjoyed this session. It was the most challenging workshop I attended despite it’s focus of dealing with things at the most basic level. Kathleen kept it fun (although she could be a little intimidating) and continued to surprise everyone in the room both with the power of .NET and the dangers of our own misconceptions. She pointed out several gotcha areas and provided the reasoning behind them. This was a last minute session, but it was also one of the best.

Wish I’d Have Known That Sooner! SharePoint Insanity Demystified

My Notes:

SQL alias: use a fake name for SQL server to account for server changes/moves. Use CLICONFIG.exe on each SP server in the farm. Do NOT use DNS for this (CNAMEs). Consider using tiers of aliases for future splitting of DBs: content, search, services – all start with the same target and changed as needed

SiteCollections can be same as ContentDBs but 100 GB is as high with OOTB tools

Limit of 60 million items per ContentDBs (each version counts)

Remote BLOB storage: SP is unaware. Common performance measurements are mostly inaccurate because they are based on single files. Externalizing all BLOBs is significant performance boost. 25-40%! Storage can be cheaper too but complexity increases. Using a SAN allows you to take advantage of SAN features (ie deduplication – which really reduces storage footprint). RBS OOTB is fine, but you can’t set business rules.

Office Web Apps no longer run on SP servers in 2013. These are great, test on SkyDrive consumer.

AD RMS allows the cloud to be more secure than on-premise. Allows exported documents to have rights management that restricts actions regardless of location. Very difficult to setup infrastructure. Office365 has this which is compelling reason to migrate.

User Profile DB is extremely important and becomes much more so in SP 2013

Claims Authentication is apparently a dude pees on a server and then gets shot with lasers:

Pee on a server

LASERS!

Upgrade to 2013 should be done as quickly as possible. Much easier than 7-10. Fully backward compatible. Both 14 & 15 hives.

Governance is very important!

Key Insights:

Preparing for growth up front with SQL aliases is a great idea

Nintex and Office 365 both need more investigation by me

Remote Blob Storage is a good idea for nearly everyone – very different perspective than what I’ve previously been told!

Overall Impression:

This session was full of great tips and best practice suggestions tempered with practical applications. This was exactly the kind of information I came to hear. Dan did a great job of presenting a lot of information (despite a massive drive failure just previous to the convention) while keeping it interesting. The only thing that was probably a little much was his in-depth explanation of Claims Authentication. His drawings were pretty rough and his enthusiasm for the topic didn’t really transfer to the audience. Regardless, this was a great session.

Key Insights:

LINQ isn’t actually a great way to access SP data despite Microsoft’s big push over the past couple of years.

Overall Impression:

This was a strange session. He didn’t go into enough depth about any one data access method to provide any real insight to those of us familiar with them and he moved so quick that anyone new to them would just have been overwhelmed. This session would have been better if he’d given clear and practical advise on when to use these methods rather than just demoing them. My guess is that he was trying to cover way too much information in too little time. However, I did enjoy hearing more about the Keyword Query Language since this is something I haven’t done much of and is rarely mentioned. Those tips alone made the whole session worthwhile.

to debug local cache use Google Chrome by going to: Chrome://app cache-internals

Worker() web worker allows messaging for functions

CORS allows cross domain requests

Web sockets do not have full support yet but will be very cool

Key Insights:

HTML 5 is going to dramatically change how we think of website capabilities – eventually.

Although exciting, HTML 5 has a long way to go and several of it’s most compelling features have little to no support in main stream browsers.

Overall Impression:

Christian did a good job of keeping the energy up about HTML 5 and showing off some of the cool features. Unfortunately he seemed to lose site of the big picture in favor of really detailed samples. I enjoyed the presentation but would like to have had more guidance about how to get started and what to focus on with this new style of web development.

Modernizr allows you to use HTML 5 with automatic replacements in incompatible browsers. Uses JQuery and is included automatically with VS 2012.

This stuff is not ready for the prime time except for mobile browsers. Modernizr fills in those gaps.

Box-sizing can be either border-box or content-box, which helps with the div width interpretation problem

Dude appears to hate JavaScript and HTML 5, sure love hearing a presenter complain about what we all came to learn about!

Key Insights:

Use Visual Studio 2012 with Modernizr to make HTML 5 websites

Overall Impression:

This session really annoyed me. Paul was very knowledgeable and had a lot of information to share. Unfortunately, he was so busy bashing the technology we all came to see that it was hard to know why we were even there.

Scaling Document Management in the Enterprise: Document Libraries and Beyond

My Notes:

Can store up to 50 million documents in a single document library

SP 2013 allows documents to be dragged onto the doc library in the browser to upload – no ActiveX required

When a User is a member of the default group for a site they get the links in office and on their mysite. Site Members is the default group by default, but this can be switched in the group settings. Suggests creating an additional group that contains everyone on the site and has no permissions, then this can be the default group.

Email enabled document libraries can be very helpful for receiving documents outside of your network

Big improvements in navigation using managed metadata service in SP 2013

Content type templates can use the columns as quick parts in Word

Key Insights:

Separating Site Membership from Site Permissions by creating an additional group just for managing memberships is a great idea.

A lot can be done with SP 2010 but SP 2013 will add a few key features to make things easier (drag and drop on the browser will be awesome).

Overall Impression:

The tip about site membership was worth the whole session. Additionally he reviewed a lot of the basics of content types and the content type hub. While this wasn’t particularly helpful to me, I can’t wait to get ahold of his slides for both this and his other sessions. He had way too many slides for the amount of time he was given.

This session reminded me of how powerful SharePoint is at so many things. Document management is not a particularly exciting topic to me but it is one of the key reasons we are using the SharePoint platform. A review of the features available to maintain the integrity of our data and to simply the classification of that data was very helpful.

Inventory lists in IT admin, also DHCP lease reports using powershell to dump that information.

List for user requests. WF for approvals, then Powershell took care of approved memberships directly in AD.

Used a list for password resets. Powershell would set password to generic password as requested (scheduled task every 5 min)

Powershell script to create team sites through list requests

SP will never be used to broadcast the Olympics but very effective to manage those teams

You must understand your users and build to what users really want/need

Don’t overwork, don’t over brand – It just clutters.

Don’t over deliver or over train.

Key Insights:

Keeping global navigation centralized in a single location (without including everything) and providing contextual navigation as needed can keep things simple from a management perspective while still allowing things to be intuitive.

Ensuring all navigation needed is exposed through the Quick Launch eliminates the need for All Site Content (except for Admin) and ensures your sites are laid out well

As long as you allow users to easily return to the global navigation from any sub site (Using the site icon is very intuitive) there is no need to clutter every site with complicated menu trees.

Request lists and Scheduled Tasks running Powershell Scripts can be used to create easy to manage but very powerful automation.

Removal of “I like it” and notes icons is a good idea

Embedding instructions directly on a given site/list using OOTB editing tools can increase usability dramatically

InfoPath List forms can go a long way towards improving list usability by making things appear more intuitive and providing in line instructions.

There are so many cool things in SP it can be easy to forget all the amazing things you can do using simple OOTB functionality. It is far too tempting to over deliver and over share when end users really only want to get their job done in the simplest way possible.

Overall Impression:

This was the best session I attended and made the entire conference worthwhile. It is unfortunately rare that you can see SP solutions in the context of an entire site. Seeing how SP was used to help manage one of the largest and most daring projects I can imagine was both inspiring and reassuring.

Besides the several tips of things they did (many of which will soon be showing up in our environment), he was able to confirm several things we were already doing that we were a little unsure about. Even better was his focus on simplifying things. I get so excited about SP features that sometimes I overuse them or forget the real power of simple lists. It was a fantastic reminder that we are often over delivering and therefore complicating things that just make SP scary and hard to use for end users.

Convention Summary

DevConnections 2012 was great. I had a great time in Vegas and I brought home several insights that have immediate practical value. Really, there’s not much more you can ask for in a technical convention.

Applies To: C#, VB.NET, Cisco Phones

I often get interrupted during the day. This is irritating but a part of office life and you get used to it. What I can’t seem to get used to, however, is hearing the same 3 hour story about my coworker’s dog’s stranger anxiety and all the mundane solutions they tried in order to fix poor Rover and even though that veterinarian is a “sweetheart” they just don’t know what they’re talking about sometimes blah blah blah – EVERY SINGLE DAY OF MY LIFE. I often find myself in conversations I neither started nor encouraged to continue that have long since passed the polite listening timeout.

Generally a good strategy is to get a friendly coworker to come and rescue you. Unfortunately, they may not always be around or may not have noticed. Another option is to fake a call. If you’ve got a Cisco IP Phone sitting on your desk and don’t mind writing a little code, you can have a handy app in just a few minutes that can send disarm the Chatinators*. Even if you are able to fully function in society without the help of fake social cues, you might find it interesting what you can do with that phone on your desk.

Cisco IP Phones can accept a wide variety of commands and it’s worth taking a look at the documentation sometime. The basic idea, however, is to send the phone an HTTP Post with some XML. In this case we are going to use the ExecuteItem command with a URI. That URI will contain a Play command. Sound confusing? It is a little, but that’s why I’m going to provide the code for you to cut and paste.

In line 5 we setup the HttpWebRequest object to send the POST to the phone. The URL that accepts the commands is either your phone’s IP Address or DNS entry followed by “/CGI/Execute“. To find your phone’s IP Address, press the settings button on the device. There should be a Phone Information section that will have your phone’s address. You may also see an entry for Host Name. This is the name of your phone and will often be the DNS entry for it. In my case it was the fully qualified version of this host name. So SEP#####.domain.com. If you are unsure, just use the IP Address and look at the response in Fiddler or something similar.

Lines 6-11 setup all the required properties to make this POST acceptable to the phone. Depending on your network settings, you’ll need to provide a username and password. This means writing programs that cause other people’s phones to ring or display funny pictures is going to be extra hard. For our phones, our AD accounts were all that was needed to authenticate with the phones. If you were given a website to configure your phone’s address book or speed dials, it’s going to be the same login information. The PreAuthenticate setting is not required, but does reduce the number of 401 challenge responses when sending multiple commands in succession.

We write out the body of the response in lines 13-17 using UTF8 and a URL Encoded XML String that starts with XML=. Finally we close the request and capture the phone’s response as XML and return it in lines 19-32.

Okay, so now we can send a command, but what does the command look like? A basic play command looks like this:

For a fake ring program, priority 2 is best. That way you don’t get any extra ringing if someone actually is trying to call you.

The second attribute, URL, can take an actual URL to more commands or a simple URI depending on what your phone accepts. More information can be found in that documentation I mentioned, but for what we’re doing a simple Play followed by a colon and the name of the ringtone file takes care of things.

So now you’ve got the command and a send command function. You can write whatever fancy code you want to wrap these things up. I’ve written a little taskbar app that listens for a global key press and sends rings in a configurable loop to the phone. This allows me to secretly reach for the keyboard while the talker is distracted. Most of that’s beyond this article, but I will show you my Ring method and let you fill in the blanks:

The ShowSettings method is just a helper method that instantiates a Windows Form to allow some configuration. You can do something similar or just hardcode everything. Lines 6-9 are the important lines, everything else is just error handling with the assumption that the settings are wrong.

In a loop corresponding to the number of rings we want, I call line 7. This is just our SendCommand function from above. Then I wait 3 seconds and do it again.

That should get you started. Pretty soon you’ll be interrupting Talkaholics with ease. There are actually several really cool things you can do with your phone and the SendCommand function above should help you get going.

One last thing, I did a bunch of guess work with the names of the ringtones in my phone. These are configured by your administrator and may be totally different for you, but here are the ringtone filenames I found worked for me:

AreYouThere.raw

Analog1.raw

Analog2.raw

Bass.raw

Chime.raw

CiscoStandard.raw

CiscoSymphonic.raw

CiscoTechno.raw

Classic1.raw

Classic2.raw

ClockShop.raw

Drums1.raw

Drums2.raw

FilmScore.raw

HarpSynth.raw

Jamaica.raw

KotoEffect.raw

MusicBox.raw

Piano1.raw

Pop.raw

Pulse1.raw

Sax1.raw

Sax2.raw

Vibe.raw

I should note that for whatever reason sending Piano2.raw crashed my entire phone. Also, just for fun, you can take a screenshot of your phone by using the following address in your browser: http://YOURPHONEIP/CGI/Screenshot

Apples To: .NET (C#, VB.NET)

In my previous post, Prettify Your XML in .NET I showed a method for taking some XML and making it pretty (indentation, new lines, etc.). Using the method also produced the XML Declaration node for us. Unfortunately, because strings are UTF-16 encoded in .NET, the XML Declaration node generated by this method is always listed as “utf-16” which may not always be what we want.

As mentioned you can see that encoding=”utf-16″. But what it you want something else (Most likely UTF8)? Well, there are several ways you can do it with Streams, XMLWriter and XMLWriterSettings objects and other junk, but you can also use a neat little method I found on Project 20 which involves subclassing the StringWriter class. (This idea originally comes from Jon Skeet).

So, just add a new class to your project and call it StringWriterWithEncoding or something similar and override the Encoding property. Here is the entire class:

Public Class StringWriterWithEncoding
Inherits IO.StringWriter
Private _encoding As System.Text.Encoding
Public Sub New(encoding As System.Text.Encoding)
MyBase.New()
_encoding = encoding
End Sub
Public Sub New(encoding As System.Text.Encoding, formatProvider As IFormatProvider)
MyBase.New(formatProvider)
_encoding = encoding
End Sub
Public Sub New(encoding As System.Text.Encoding, sb As System.Text.StringBuilder)
MyBase.New(sb)
_encoding = encoding
End Sub
Public Sub New(encoding As System.Text.Encoding, sb As System.Text.StringBuilder, formatProvider As IFormatProvider)
MyBase.New(sb, formatProvider)
_encoding = encoding
End Sub
Public Overrides ReadOnly Property Encoding As System.Text.Encoding
Get
Return _encoding
End Get
End Property
End Class

So all we’ve really done is provided constructors that allow us to specify the encoding the StringWriter object should use. Then we’ve overriden the Encoding property to always return the value specified in the constructor. The result is the StringWriter uses our encoding. So then we can take the PrettyXML code and swap the StringWriter object creation to a StringWriterWithEncoding like so: