Debugging Sitecore dlls

Applies To: Sitecore, ASP.NET, Visual Studio

Recently I was experimenting with Sitecore’s Linq based search. I was having an issue with my facets (perhaps if I ever solve it I’ll write about that too) and I wanted to look into how these were actually created within the Sitecore code.

Using .NET Reflector I was able to decompile the Sitecore.ContentSearch.Linq dll and take a look at the code. (You can do this in the .NET Reflector Object Browser within Visual Studio if you have the .NET Reflector plugin installed). In order to debug it I had to select the Debug option in the same window. This generates the proper symbols and tells Visual Studio to use them. This is really awesome and you can begin walking through your code (Attach to Process w3wp.exe).

Unfortunately, I was unable to see the values of any variables. When attempting to evaluate them I was getting:

Cannot obtain value of local or argument ‘[varablename]’ as it is not available at this instruction pointer, possibly because it has been optimized away.

This is one of those rare cases where the message was actually related to the cause. In order to see those values of the decompiled Sitecore dlls and any other dlls in .NET you need to disable optimization.

“Great!” you shout while working alone in a darkened room full of loneliness. A quick trip to Google reveals you simply need to create an ini file with the same name as the dll with the following values:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

In my case I named this file Sitecore.ContentSearch.Linq.ini. Super easy, wow! But then nothing happens. Placing this file next to the dll file in the bin directory won’t accomplish anything. You will need to place it where the dll is actually living while the website is running.

To find this special place, attach to the process like normal and then choose DEBUG > Windows > Modules form within Visual Studio. This will show you all the dlls that are being used. Scroll down to the dll you want to target and copy the path (it’s probably somewhere in the Temporary ASP.NET Files) and open it in Windows Explorer. Copy your ini file there.

Stop debugging and re-attach to the process. Now you can see the values! Soon you will see the issue is probably your own code, but isn’t it nice to pretend it’s somebody else’s fault? You bet it is!

Hakin

Now you big time hacker!

Embedded Chromium in WinForms

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:

CefSharpWinFormsNuGet

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 BUILDConfiguration 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:

ConfigurationManager

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:

Imports CefSharp.WinForms
Imports CefSharp

Public Class Form1

    Private WithEvents browser As ChromiumWebBrowser

    Public Sub New()
        InitializeComponent()

        Dim settings As New CefSettings()
        CefSharp.Cef.Initialize(settings)

        browser = New ChromiumWebBrowser("http://thechriskent.com") With {
            .Dock = DockStyle.Fill
        }
        panBrowser.Controls.Add(browser)

    End Sub
End Class

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:

WinFormsBasicBrowser

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:

Imports CefSharp
Imports System.IO
Public Class LocalSchemeHandler
    Implements ISchemeHandler

    Public Function ProcessRequestAsync(request As IRequest, response As ISchemeHandlerResponse, requestCompletedCallback As OnRequestCompletedHandler) As Boolean Implements ISchemeHandler.ProcessRequestAsync
        Dim u As New Uri(request.Url)
        Dim filepath As String = u.Authority & u.AbsolutePath

        If File.Exists(filepath) Then
            Dim bytes As Byte() = File.ReadAllBytes(filepath)
            response.ResponseStream = New MemoryStream(bytes)
            Select Case Path.GetExtension(filepath)
                Case ".html"
                    response.MimeType = "text/html"
                Case ".js"
                    response.MimeType = "text/javascript"
                Case ".png"
                    response.MimeType = "image/png"
                Case ".appcache" OrElse ".manifest"
                    response.MimeType = "text/cache-manifest"
                Case Else
                    response.MimeType = "application/octet-stream"
            End Select
            requestCompletedCallback()
            Return True
        End If
        Return False
    End Function

End Class
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:

        Dim settings As New CefSettings()
        settings.RegisterScheme(New CefCustomScheme() With {
                                .SchemeName = LocalSchemeHandlerFactory.SchemeName,
                                .SchemeHandlerFactory = New LocalSchemeHandlerFactory
                                })
        CefSharp.Cef.Initialize(settings)
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:

<!DOCTYPE html>
<html>
    <body>
        <h1>My First Heading</h1>
        <p>My first paragraph.</p>
        <img src="images/truck.png"/>
        <script type="text/javascript">
            console.log("Hello from the console!");
            //alert("Hello from a dialog!");
        </script>
    </body>
</html>

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

truck

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:

LocalResource

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:

    Private Sub onBrowserConsoleMessage(sender As Object, e As CefSharp.ConsoleMessageEventArgs) Handles browser.ConsoleMessage
        If e.Line > 0 Then
            addActivity(String.Format("CONSOLE: {0} ({1}|{2})", e.Message, e.Source, e.Line))
        Else
            addActivity(String.Format("CONSOLE: {0}", e.Message))
        End If
    End Sub

    Private Sub addActivity(Message As String)
        If txtActivity.InvokeRequired Then
            txtActivity.Invoke(New Action(Of String)(AddressOf addActivity), Message)
        Else
            txtActivity.AppendText(Message & vbCrLf)
        End If
    End Sub

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:

ConsoleActivity

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:

dialogMsgBox

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:

Imports CefSharp
Public Class LogDialogHandler
    Implements IJsDialogHandler

    Private logReceiver As Action(Of String)

    Public Sub New(LogReceiverAction As Action(Of String))
        logReceiver = LogReceiverAction
    End Sub

    Public Function OnJSAlert(browser As IWebBrowser, url As String, message As String) As Boolean Implements IJsDialogHandler.OnJSAlert
        logReceiver(String.Format("ALERT: {0}", message))
        Return True
    End Function

    Public Function OnJSConfirm(browser As IWebBrowser, url As String, message As String, ByRef retval As Boolean) As Boolean Implements IJsDialogHandler.OnJSConfirm
        logReceiver(String.Format("CONFIRM: {0}", message))
        retval = True
        Return True
    End Function

    Public Function OnJSPrompt(browser As IWebBrowser, url As String, message As String, defaultValue As String, ByRef retval As Boolean, ByRef result As String) As Boolean Implements IJsDialogHandler.OnJSPrompt
        logReceiver(String.Format("PROMPT: {0} ({1})", message, defaultValue))
        result = defaultValue
        retval = True
        Return True
    End Function
End Class

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:

browser.JsDialogHandler = New LogDialogHandler(New Action(Of String)(AddressOf addActivity))

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:
AlertActivity

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:

    Private Sub btnDevTools_Click(sender As Object, e As EventArgs) Handles btnDevTools.Click
        browser.ShowDevTools()
    End Sub

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

DevTools

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.

DevConnections 2012

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?

Asif RehmaniSharePoint-Videos.com

My Notes:

  • Always use browser first when possible
  • Anything Enterprise wide should be VS or buy
  • DVWP also called Data Form WP
  • DVWP multiple sources to XML with XSLT
  • LVWP specific to SP lists
  • Browser limits in views don’t apply in Designer (Grouping, Sorting, etc.)
  • Import Spreadsheet is only through browser – NOT SP Designer
  • Conditional Formatting in views including icons (put all icons in cell and change content conditional formatting on each).Pictures automatically go in SiteAssets
    • Sometimes img uploads retain local path (switch to code and correct src url)
  • 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.


Data Visualization: WPF, Silverlight & WinRT

Tim HuckabyInterknowlogy

My Notes:

  • WPF is great at 3D, cool demo of scripps molecule viewer (codeplex)
  • Silverlight is dead
  • Winforms is dead
  • HTML 5 hysteria is in full swing
  • HTML 5 has a canvas and SVG support
  • ComponentOne has neat HTML 5 sales dashboard demo

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.


Building Custom Applications (mashups) on the SharePoint Platform

Todd Baginski – http://toddbaginski.com/blog/

My Notes:

  • Used Silverlight but recommends HTML 5
  • Suggests that all mashups should be Sandbox compatible
  • Bing Maps has great examples requiring little work
  • SL to SL: localmessagesender use SendAsync method. In receiver setup allowedSenderDomains list of strings. Use localmessagereceiver and messagereceived event. Be sure to call the listen() method!!
  • Assets Library great for videos
  • Silverlight video player included in SP 2010/2013. 2013 has an additional fallback HTML 5 player.
  • External Data Column: Works as lookup for BCS
  • OOTB \14\TEMPLATE\LAYOUT\MediaPlayer.js: _spBodyOnLoadFunctionNames.push(‘mediaPlayer.createOverlayPlayer’); after you’ve made links hook ‘em up: mediaPlayer.attachToMediaLinks((document.getElementById(‘idofdivholdinglinks’)), [‘wmv’,’mp3′]);
  • 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.
  • SL JS call: HtmlPage.Window.Invoke(“Jsfunctionname”, new string[] { parameter1, parameter2})
  • JQuery twitter plugin
  • SP 2013 has geolocation fields. Requires some setup & code. He has app to add GL column & map view to existing lists.
  • Even in SP 2013 the supported video formats are really limited
  • 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.


Creating Mobile-Enabled SharePoint Web Sites and Mobile Applications that Integrate with SharePoint

Todd Baginski – http://toddbaginski.com/blog/

My Notes:

  • AirServer $14.99 shows iPad on computer
  • Mobile is much better in SP 2013
  • Device channel panel allows content to target specific devices

Key Insights:

  • Mobile is important. You can struggle with SP 2010, but you should probably just upgrade to SP 2013

Overall Impression:

I enjoyed Todd’s other session (see above), but this one was too focused on SP 2013 to have any real practical value for me.


Getting Smarter about .NET

Kathleen Dollard – http://msmvps.com/blogs/kathleen/

My Notes:

  • Lambdas create pointers to a function
  • LINQ creates expressions that can be evaluated everywhere
  • 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

Dan Holme – Intelliem

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
  • ContentDB sizing: change initial size and growth. Defaults are 50mb and 1mb growth. Makes a BIG difference in performance.
  • ContentDBs can be up to 4 TB. Over 200 GB is not recommended.
  • 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.
  • Get office365 preview account
  • Nintex highly recommended over InfoPath. InfoPath is supported but unenhanced in 2013, likely indicator of unannounced strategy.
  • 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.


SharePoint Data Access Shootout

Scot Hillier – http://www.shillier.com

My Notes:

  • LINQ cannot query across multiple lists (unless there is a lookup connection)
  • SPSiteDataQuery can query all lists of a certain template using CAML within a Site or Site Collection
  • SPMetal.exe generates Object Relational Map needed for LINQ  (in hive bin)
  • LINQ isn’t going to have much support in SP 2013
  • SP 2013 has continuous crawl
  • Keyword Queries are very helpful
  • KQL: ContentClass determines the kind of results you get. (ie STS_Web, STS_Site, STS_ListItem_Events)
  • Search in 2013 provides a rest interface to use KQL in JavaScript
  • CSOM is very similar to Serverside OM
  • CSOM is JS or .NET

Key Insights:

  • Keyword Query Language (KQL) needs more consideration as an effective query language for SharePoint.
  • 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.


HTML5 JavaScript APIs: The Good, The Bad, The Ugly

Christian Wenz – http://www.hauser-wenz.de/s9y/

My Notes:

  • HTML5 is a large umbrella of technologies
  • Suggests Microsoft WebMatrix is a good Editor
  • Semantics for HTML elements is a powerful new feature: input type = email, number, range, date, time, month, week, etc. These customize the type of editor and adds validation
  • Suggests Opera Mobile Emulator is a good testing tool
  • Additional elements: aside, footer
  • Requesting location: navigator.geolocation.getCurrentPosition(function(result){console.log(result)});
  • 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.


Roadmap: From HTML to HTML 5

Paul D. Sheriff – http://weblogs.asp.net/psheriff/

My Notes:

  • Lots of new elements – but they don’t do anything. They make applying CSS easier and allow search engines to parse through a page easier.
  • Browsers that don’t understand new elements will treat them as divs – but styles won’t be applied.
  • Lots of new input types (color, tel, search, URL, email, number, range, date, date-time, time, week, month)
  • New attributes (autofocus, required, placeholder, form validate, min, max, step, pattern, title, disabled)
  • CSS3 has huge style upgrades but there are still a lot of browser incompatibilities
  • JqueryUI, Modernizr = good tools, use VS 2012 with IE10 or Opera
  • 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

Dan Holme – Intelliem

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
  • Pingar is a recommended product he briefly mentioned
  • 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.


SharePoint in Action: What We Did at NBC Olympics

Dan Holme – Intelliem

My Notes:

  • Keep SharePoint simple. Use OOTB features as much as possible
  • 300 hours of content broadcasted per day
  • NBCOlympics.com streamed every competition live
  • Most watched event in TV history
  • 3,700 NBC Olympics team members
    • 1 SP admin/support
  • PDF viewing was turned on despite security concerns
  • Set as default IE page – very difficult to do, they used a script to set a registry entry to account for multiple OSs and browser versions
  • All additional web applications were exposed through SP using a PageViewer WP
    • Phone Directory, Calendar application
  • WebDAV was used to allow other apps to publish documents
  • Global Navigation on top site using tabs (drop down menus)
    • Quick launch had contextual items to site
    • Navigation centric homepage, kept navigation as simple as possible. Only homepage had global navigation.
  • No real branding (put picture on right and used a custom icon). They set the site icon to go to the main web page because it’s what users expected.
  • Did not use lists or libraries as terms instead used Content (libraries, other lists) and Apps (Calendar, Tasks, etc.)
  • Suggests hiding “I like it” and notes since they are not helpful and deprecated in SP 2013
  • Site mailboxes for teams using OWA
  • Embedded documentation: Put basic instructions right on the homepage of team sites as needed. Also above some document libraries – basic upload and open instructions.
  • Focus on usability since there was no time for training
  • Took out All Site Content link and all other navigation was on homepage of site. Sub sites had tab links to parent site.
  • Used InfoPath to customize List Forms mostly to add instructions (placed below field title on left)
  • Lots of calendars. Conference room calendars were very popular. Didn’t use exchange for this in order to accommodate outside users.
  • Used InfoPath lists and workflows to replace paper processes. Kept them simple but effective. Although not used in this case, he recommends Nintex for more advanced needs.
  • Self-service help desk: printer/app installs, FAQs. Showed faces of team.
    • PageViewer web part and point it to \\servername to show all printers and put instructions on right to get those installed directly out of SP
    • Kept running FAQ to show common solutions
  • IT Administration site: ticket system used issue tracking list highly customized with InfoPath list forms.
    • 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.

Make Your Cisco IP Phone Ring Using .NET

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.

To send a command using VB.NET, you can use this helper function:

    Private Function SendCommand(Address As String, Command As String, Username As String, Password As String) As String

        Dim ResponseXML As String = String.Empty

        Dim request As HttpWebRequest = WebRequest.Create(String.Format("http://{0}/CGI/Execute", Address))
        request.Timeout = 30 * 1000
        request.Method = "POST"
        request.Accept = "*/*"
        request.ContentType = "application/x-www-form-urlencoded"
        request.Credentials = New NetworkCredential(Username, Password)
        request.PreAuthenticate = True

        Dim bytes As Byte() = Encoding.UTF8.GetBytes(String.Format("XML={0}", HttpUtility.UrlEncode(Command)))
        Using outStream As Stream = request.GetRequestStream
            outStream.Write(bytes, 0, bytes.Length)
            outStream.Close()
        End Using

        Using response As WebResponse = request.GetResponse
            Using responseStream As Stream = response.GetResponseStream
                Using reader As New StreamReader(responseStream)
                    If reader IsNot Nothing Then
                        ResponseXML = reader.ReadToEnd
                        reader.Close()
                    End If
                    responseStream.Close()
                End Using
            End Using
            response.Close()
        End Using

        Return ResponseXML
    End Function

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:

<CiscoIPPhoneExecute><ExecuteItem Priority="2" URL="Play:Classic1.raw" /></CiscoIPPhoneExecute>

It’s pretty straightforward XML. The ExecuteItem element has 2 attributes, Priority and URL. The Priority attribute can be set from 0 to 2:

  • 0 = Execute Immediately (The command takes priority over anything else the phone might be doing)
  • 1 = Execute When Idle (The command waits until the phone isn’t busy before executing)
  • 2 = Execute If Idle (The command executes if the phone isn’t busy, otherwise it’s ignored)

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:

    Private Sub Ring()
        If String.IsNullOrEmpty(My.Settings.PhoneIP) Then
            ShowSettings()
        Else
            Try
                For i As Integer = 0 To My.Settings.RingRepeat - 1
                    SendCommand(My.Settings.PhoneIP, String.Format("<CiscoIPPhoneExecute><ExecuteItem Priority=""2"" URL=""Play:{0}"" /></CiscoIPPhoneExecute>", My.Settings.RingTone), My.Settings.Username, My.Settings.Password)
                    If i < My.Settings.RingRepeat - 1 Then Threading.Thread.Sleep(3000)
                Next

            Catch wex As WebException
                MsgBox("Error when talking to the phone, please check your settings!" & vbCrLf & "(Probably your credentials)" & vbCrLf & vbCrLf & wex.ToString, MsgBoxStyle.Critical, "No Ring Ring :(")
                ShowSettings()
            Catch ex As Exception
                MsgBox("Error when talking to the phone, please check your settings!" & vbCrLf & vbCrLf & ex.ToString, MsgBoxStyle.Critical, "No Ring Ring :(")
                ShowSettings()
            End Try
        End If
    End Sub

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

*Chatinators © 2012 (and for all time), Chris Kent

Prettify Your XML in .NET

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

If you do much work with XML in either VB.NET or C# you’re probably looking for a way to control it’s formatting and make it look “pretty”. This has come up a few times for me so I thought I’d share a quick method for doing this.

Most often I’m using this to format XML from Web Services (Mostly SharePoint) or to take a look at XML I’ve generated for Web Services to see what’s wrong. But for this example, I’ve got a couple of helper functions that generate some XML using objects from the System.Xml namespace. Here’s how I generate the XML used here:

    Private Function GetXML() As String
        Dim doc As New XmlDocument
        Dim rn As XmlNode = doc.CreateElement("TMNT")
        Dim sn As XmlNode = doc.CreateElement("Turtles")
        sn.AppendChild(CreateTurtleNode(doc, "Leonardo", "Blue", "Katana"))
        sn.AppendChild(CreateTurtleNode(doc, "Raphael", "Red", "Sai"))
        sn.AppendChild(CreateTurtleNode(doc, "Michelangelo", "Orange", "Nunchaku"))
        sn.AppendChild(CreateTurtleNode(doc, "Donatello", "Purple", "Bo"))
        rn.AppendChild(sn)
        doc.AppendChild(rn)
        Return doc.InnerXml
    End Function

    Private Function CreateTurtleNode(doc As XmlDocument, Name As String, Color As String, Weapon As String) As XmlNode
        Dim tn As XmlNode = doc.CreateElement("Turtle")
        Dim na As XmlAttribute = doc.CreateAttribute("Name")
        na.Value = Name
        tn.Attributes.Append(na)
        Dim ca As XmlAttribute = doc.CreateAttribute("Color")
        ca.Value = Color
        tn.Attributes.Append(ca)
        Dim wa As XmlAttribute = doc.CreateAttribute("Weapon")
        wa.Value = Weapon
        tn.Attributes.Append(wa)
        Return tn
    End Function

This is just sample code to get some unformatted XML and if you display the results of the GetXML function, here’s what you get:

<TMNT><Turtles><Turtle Name=”Leonardo” Color=”Blue” Weapon=”Katana” /><Turtle Name=”Raphael” Color=”Red” Weapon=”Sai” /><Turtle Name=”Michelangelo” Color=”Orange” Weapon=”Nunchaku” /><Turtle Name=”Donatello” Color=”Purple” Weapon=”Bo” /></Turtles></TMNT>

This isn’t terrible and if you’re just using this in your code, no worries! But if you want to display this to an end user or even yourself, proper lines and indentation can make a huge difference – especially since your XML is almost guaranteed to be more complex than my example above.

There are some crazy examples out there of reading through the string and manually inserting line returns and spaces when detecting the less than or greater than symbols. These are usually error prone and won’t take into account all the various possibilities for XML. They’re inefficient, ugly, and lame. Fortunately, there are some helpful objects in the System.IO namespace and the System.Xml namespace that make all of this very easy. Here’s the function:

    Private Function PrettyXML(XMLString As String) As String
        Dim sw As New StringWriter()
        Dim xw As New XmlTextWriter(sw)
        xw.Formatting = Formatting.Indented
        xw.Indentation = 4
        Dim doc As New XmlDocument
        doc.LoadXml(XMLString)
        doc.Save(xw)
        Return sw.ToString()
    End Function

I imagine this could be improved (feel free to share in the comments), but it definitely does the job. The key elements are the XmlTextWriter’s properties Formatting and Indentation. There are several other properties and methods you can use to customize even further, but the above produces a fairly nice result:

<?xml version="1.0" encoding="utf-16"?>
<TMNT>
    <Turtles>
        <Turtle Name="Leonardo" Color="Blue" Weapon="Katana" />
        <Turtle Name="Raphael" Color="Red" Weapon="Sai" />
        <Turtle Name="Michelangelo" Color="Orange" Weapon="Nunchaku" />
        <Turtle Name="Donatello" Color="Purple" Weapon="Bo" />
    </Turtles>
</TMNT>

Now all the lines and indentation are there as expected! We even get the nice XML Declaration free of charge.