Wednesday, July 9, 2014

Exception from HRESULT: 0x80131904 Caused by missing LookupID="True"

I was running the following query when I unexpectedly got this cryptic error: Exception from HRESULT: 0x80131904.


 
   
     
       
        11
     
   
 
  1


PersonFieldName person/group field cannot be compared directly to the integer value 11. This somehow caused the error message which certainly does not indicate anything related to the actual mistake that I have made. One must indicate that we want to compare the Id of PersonFieldName in the FieldRef element, to the integer value in the Value element. We do that simply by adding the attribute LookupId and set its value to "TRUE" as follows:



Why didn't someone just throw new InvalidOperationException("Cannot compare field of type Person/Group to integer value.");

What's more interesting is that this very same error message seems to appear when other kinds of problems occur. Looks like some part of SharePoint's code is missing proper exception handling. See this blog post about receiving the same error message for memory capacity problems!

Saturday, June 28, 2014

IE Compatibility view to add complications to web design

This is interesting and shocking at the same time. Why would IE 9 for one user display your site incorrectly while for another displays correctly?

Compatibility View. This "Feature" let's your modern browser behave like a really old one, this is useful depending on what mental illness you have.

Anyways, psychological problems aside, it is not just that your IE 8, 9, 10 or 11 might suddenly behave like the IE 7 that you no longer support, and as thus have users who enable the view acceidentally have bad user experience with your site, it is not even as simple as that.

When I discovered that my design was not working for some users because of compatibility view, I started to investiage and found out the following MSDN article: http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx

The article mentioned that:
In Windows Internet Explorer 9 and earlier versions, quirks mode restricted the webpage to the features supported by Microsoft Internet Explorer 5.5.

So we also have Quirks Mode, which occurs when you omit the HTML page's DOCTYPE, to add complexity to your web design life (ON IE!). Unfortunately a significant percentage of my audience uses IE 9 for my current project.

This is why I had to use x-ua-compatible and set the supported IE browsers like so:



This means, I support Edge (shouldn't I?!), if Edge is not available, then I support IE 10, if that's not available then IE 9 and so on... This will disallow the user to incorrectly turn on "In"compatibility view. And this will ease testing as you can rest assured that what you see on your modern browser is that same as what your beloved client will see.

Sunday, June 15, 2014

SharePoint Internal Field Names for Modified By and Created By (editor and author)

Given SharePoint's endless number of peculiarities, I think it is debatable whether it is surprising or not whether a simple attempt to access the "Modified By" field of an item fails simply by saying that the field does not exist on the item.

var item = list.GetItemById(70);
context.Load(item, x => x["ModifiedBy"]);
context.ExecuteQuery(); //BOOM!

Going to the item's list and checking the column, it will clearly show "Created By" and "Modified By". Using REST, I found out that the fields are called "AuthorId" and "EditorId" respectively.

//STILL BOOM

Then I tried with "Author Id".

//STILL BOOM!

Finally I searched through the user fields returned by list.Fields. That's when I found a Microsoft.SharePoint.Client.FieldUser with EntityPropertyName property of value 'Editor'. The other is 'Author'.

var item = list.GetItemById(70);
context.Load(item, x => x["Author"]);
context.ExecuteQuery(); //NOT BOOM... But still not really exciting.

Here you go. You got the author, what are you going to do with it? Finally invent Time Travel?

Saturday, June 7, 2014

Web Part 2: Showing Site Contents in SharePoint 2013

It's funny how in SharePoint, sometimes the simplest things require a lot of effort to be done. For example, I want site the Site Contents to show to the user when they browse to the site. So the home page should contain a list of the existing lists, document libraries and other applications (the contents of the site). This is because for one site, the user does not need anything on the home page so they've left it blank. This causes confusion and people think the site is empty because the home page is, while in fact if they go to Site Contents, they'll find everything they'd expect.

I intuitively thought that there must be a built-in web part that I can just use. I consider using both the Page Viewer web part and the automatically created web parts for the added apps but both turned out not to be good enough. I ended up writing a web part specifically for the purpose of showing a list of libraries and lists that exist in a site and here's why, and then how:

Using the automatically created web parts for the added apps

When a document library or list are created, Web Parts showing their contents become available under the Apps category as shown below. Notice that the Apps category is selected and it shows Web Parts with the same name as Document Libraries and Lists that actually exist in the site.

This is obviously not practical unless you only have a couple of document libraries and lists. If you have more, then you'll end up with a long home page that is unfriendly to browse.

Using the Page Viewer web part

Under the Media and Content web part category, you can find the Page Viewer web part which is used to view any other page by setting a url. I used this and set the URL to the viewlsts.aspx SharePoint page that shows the Site Contents. It works perfectly if you add the IsDlg=1 query string parameter in the URL.

Location of the Page Viewer web part

Here's how to set the page URL to viewlsts.aspx:

  1. Click open the tool pane and screen with settings to configure the web part will show
  2. Enter the URL to viewlsts.aspx and don't forget the isdlg=1 parameter. if you omit this parameter you will get a full SharePoint page, with the ribbon and header displayed and that's ugliness is surely not what you want. This page shows the site contents in a small box as show below.
  3. press OK for dissatisfaction (for the two reasons, read on).
This didn't work for me for two reasons:
  1. The web part assumes a small margin of the page (the settings say to adjust the height, but apparently it does no work). My biggest problem is that I didn't even get a scroll bar on the live server when I tried this.
  2. Recursive embarrassment: I decided to go with it as I wanted a quick no-code solution. So I adjusted the height to something fixed, say 1000 pixels (which is bad practice). The recursive embarrassment occurs when you try to navigate to lists and documents displayed. Turns out, even applying the isdlg=1 parameter, does not change how the links work, so clicking the links will display a page that is not a dialog. This enables you to have a page inside a page inside a page and so on! See this:

When a dialog opens a page, it should be also a dialog page, no? Anyways, this solution now is shown to be useless.

I ended up writing a web part. And I am still surprised that such basic functionality is not built in. I searched online before doing so because I strongly believed that such trivial task would have come to the minds of the builders of the web part templates, but I only found things about time table web part (Server version only, I needed something that works on Foundation) and the above page viewer hack which was embarrassing because of some recursive functionality that made the page look like it's in another page and that page was into another AND SO ON, even if I use IsDlg=1.

Finally here's how to solve this issue:

How to show Site Contents in a Web Part:

This is just a small tiny reason to why I prefer development over administration. Write the code to fix the problem rather than click here and there looking for things which isn't even automatable! Code is easy and works fine and can be tailored to Exactly what you want:

This code is within the page of a Visual Web Part (which is just a web part!) Visual Studio project.

List<SPList> leests = new List<SPList>();
protected void Page_Load(object sender, EventArgs e)
{
    leests.Clear();
    //SPUtility.MapToIcon
    foreach (SPList l in Microsoft.SharePoint.SPContext.Current.Web.Lists)
        this.leests.Add(l);
 
    //get the lists (document libraries and item lists) that are not hidden and sort them by creation date
    leests = leests.Where(x => !x.Hidden).OrderBy(x => x.Created).ToList();
}

And the following mark up (remember this is a visual web part project):

<div id="contentList" runat="server">
            
    <% foreach (SPList l in this.leests) { %>
        <div>
            <a href="<%=l.DefaultViewUrl%>">
                <img src="<%= l.ImageUrl%>" alt="<%= l.Title %>" />
                <%: l.Title %>
            </a>
        </div>
    <%%>
</div>

That's it! Done! Had I just coded it from the start, I would have solved the problem quicker. The only thing I had to look up was the ImageUrl (for the icon of the document libraries and lists and others, so that it would show nicely). Here's the end result:


Tuesday, June 3, 2014

Person or Group field in SharePoint

Using the Client Side Object Model.

You can assign a User object to a list field that is "Person or Group" field. For example the following code example shows how to assign the current user to a field called "Person" on a newly created item. The "Person" field is defined as "Person or Group" with multi-selection disabled.



var context = /*get it from somewhere, if you're new, good luck :)*/
            var list = context.Web.Lists.GetByTitle("test");
            var item = list.AddItem(new ListItemCreationInformation());
            item["Person"] = context.Web.CurrentUser;
            item.Update();
            context.Web.Update();
            context.ExecuteQuery();

So this obviously demonstrates that I can assign a Microsoft.SharePoint.Client.User object, which inherits from Principal in the same namespace. Intuitively (but incorrectly) I tried to assign an array of these User objects to another field called "People" defined in the same way as "Person or Group" but with multi-selection enabled:


An array of users didn't work, but converting that array to an array of FieldUserValue array works.

var context = Static.Context();
            var list = context.Web.Lists.GetByTitle("test");
            var item = list.AddItem(new ListItemCreationInformation());
 
            var u = context.Web.EnsureUser("surely_exists_on_SPSite@domain.com");
            //i'm loading because I need the value in the Id field to
            //init the FieldUserValue objects.
            context.Load(u);
            context.Load(context.Web.CurrentUser);
            context.ExecuteQuery();
 
            FieldUserValue fuv = new FieldUserValue();
            fuv.LookupId = context.Web.CurrentUser.Id;
 
            FieldUserValue fuv1 = new FieldUserValue();
            fuv1.LookupId = u.Id;
            item["People"] = new FieldUserValue[] { fuv, fuv1 };
            item.Update();
            context.Web.Update();
            context.ExecuteQuery();

What I found annoying here is that there is nothing to tell you what you can assign to the "People" or "Person" fields. Previous experience with the PeoplePicker control taught me that I need to use the FieldUserValue, but Intellisense is useless in this part of the world :( One primary Visual Studio feature is down!

Thursday, May 22, 2014

Thoughts on proving software correctness to non-tech savvy customers

How to prove to the client that the system works correctly?

Today a financial audit manager entered our office and asked how do I make sure that system X is really following requirement Y.

Luckily the system he is worried about is sufficiently simple to be tested using 6 use cases. You can use brute force on a test server and check them all.

Brute Force 6 use cases? Sure why not, is there any other option anyways?

There should be another option. What if we have 6000 use cases? That makes brute force even a more suitable option, given opportunities to automate tests programmatically, but these won't be so convincing to someone who enjoys even doubting the correctness of tests. Wait, how will write all those tests?

What if we have a system whose dynamism make us unable to explicitly state and count the use cases?

That's when brute force will not work. For an auditor to really be at peace, he or she or it actually needs to go through all those cases manually. A programmer might argue that the automated tests indicate correctness, but that might not be enough for a cautious auditor, or an auditor how is confused about some abnormalities, and he thinks that the possiblity that your system is making the tiniest mistakes in very obscure hypothetical circumstances, canoot be waived.

What's to the rescue here? DSLs? Teaching the financial auditor some code (and them teaching them to read through the business layer of your 4-tier application? They might also want to checkout the data layer too.

There is a vague idea in my head to describe system functionality in attempt to prove correctness.

To be continued.