Wednesday, July 30, 2014

Complexity Management and Software Development

The details are endless, and are of the lowest business value and complete irrelevance.

One of the primary functions in the business layer of a software system uses a generated control structure. Who cares?

All those helper methods, the similarities in the code, the necessity to handle all the errors, all the different data types, the different sources of information, the conversions between the various representations, etc.

Software Development teaches developers to management complexity which is what business management is all about.

From the code's perspective, we don't care if this object denoting a person is a chief operator or a junior operator. It's just a person whose id must be entered in this field and associated with another object that is in turn associated with an period of time.

From the business perspective, we don't care if this is an object or a magic potion. I don't care that the method that processes a chief operator is exactly the same as that of a junior operator. All I care about is that I can choose both and that the system marks them as unavailable for more work, until they finish.

This is what I love about my current job. I must care for both the business perspective and the lowest levels of code details.


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!