Thursday 12 September 2013

The one where TMG Link Translation breaks Event Validation

I had a simple ASP.NET page with the following in the markup:
   <asp:DropDownList ID="ddl" runat="server"></asp:DropDownList>
   <asp:Button ID="btn" runat="server" OnClick="btn_Click" />


And something like this in the codebehind Page_Load:
   ddl.Items.Add("https://my.domain.com/");


When clicking the button to submit the form an error occurred which after some digging turned out to be:
Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.


After much head scratching I noticed that the value I was adding (https://my.domain.com) was not what was being displayed in the browser (https://MY.domain.com). Event validation for the page was throwing the error because the value I was submitting by clicking on the button was not the value that was put into the drop down list in the codebehind.


The problem was that Link Translation was enabled in Microsoft Forefront TMG. This automatically rewrites web content so that links with internal names are change to the defined public name before they are presented to the client. In this case the public name was set to https://MY.domain.com. Since the internal and public names are the same in this case, disabling Link Translation in TMG fixed the issue.

Although event validation protects against the user submitted altered data, it would still be a better idea to have them submit an ID and look up the corresponding URL when the form is submitted.

Friday 16 August 2013

SharePoint 2013 - Querying Property Bags with Search

Property bags in SharePoint are a great way to store simple data with list items or webs. There are a few blog posts about making property bag entries searchable like this one but I couldn't find anything about being able to query them. This means that if you have a web with a property bag key and value set, the web would be returned when you search for that value (along with anywhere else it appears) but you can't search for webs where your key is set to your value. To allow this you need to set up a managed property associated to your property bag key.

  1. Set a property bag key/value pair using powershell as in the link above or using the object model like:
    myWeb.AllProperties[“myspecialkey”] = “myawesomevalue";
  2. Set it to be indexed and then update the web:
    myWeb.IndexedPropertyKeys.Add(“myspecialkey”);
    myWeb.Update();
  3. Carry out a full crawl by going to Search Administration in Central Administration, selecting Content Sources and selecting Start Full Crawl from the drop down menu of your content source.
  4. Once this has completed, go to Search Schema in Search Administration and select Crawled Properties. Search for your key (“myspecialkey”) and make sure it was indexed. If it was, you will be able to search for your value ("myawesomevalue") from your SharePoint site but this will return any results that match (e.g. web titles, list items, document metadata), you won’t be able to search for only results where your key is set to a value.
  5. To enable searching for results where your key is set to a value you need to add a managed property.
    1. In Search Administration go to Search Schema and click New Managed Property
    2. Enter a property name for the new managed property (the same name as your key is easiest)
    3. In “Mappings to crawled properties” click “Add a Mapping” and search and add your property bag key
    4. Make sure Queryable is selected. This is what lets you get only results where your key is equal to a value. If you want your key and value to be returned in the search results (when querying using one of the APIs), make sure Retrievable is enabled
    5. Select any other characteristics that you require and click OK
  6. After another full crawl you can search for key=value or key:value from a site and you should only get back results where your key is equal to your value. If you add this key to any other webs, they will be indexed when the next crawl runs without having to make any further changes in Search Administration.

Wednesday 31 July 2013

Raspbmc as a wireless bridge

I have XBMC installed on a Raspberry Pi using Raspbmc to stream content to my TV over WiFi but I wanted to make use of the Pi’s Ethernet port to give internet access to a Sky+ set top box which only has an Ethernet port.

I started with a Raspberry Pi with Raspbmc installed over WiFi using an Edimax EW-7811UN USB WiFi adapter. My home network uses the 192.168.0.0/24 subnet with my WiFi router using 192.168.0.1 and the Raspberry Pi using a static IP of 192.168.0.51.

Setting up the bridge was based heavily on the following guide which is for Raspian:
http://qcktech.blogspot.dk/2012/08/raspberry-pi-as-router.html

The following post was also helpful in starting things at boot which is an area that Raspbmc differs from the above guide:
http://forum.stmlabs.com/showthread.php?tid=3552&pid=33455#pid33455

Raspbmc doesn’t use /etc/network/interfaces so you need to edit the settings.xml file:
sudo nano /home/pi/.xbmc/userdata/addon_data/script.raspbmc.settings/settings.xml
The WiFi settings were already configured from the install but you need to setup the wired interface. Give it a static IP in the “nm.address” entry (I used 192.168.1.1), set the gateway to the same IP, set an appropriate netmask and make sure DHCP is disabled for the wired interface and finally. I set the DNS to one of Google’s (8.8.8.8) but I’m not sure if this is needed.

My final settings.xml file looked like this:


If you want your Pi to give out IP addresses to devices connected to the wired port using DHCP, you can install isc-dhcp-server using the instructions in the link mentioned earlier, but I decided to use a fixed IP for simplicity.

I found that with both the USB WiFi and wired connections being used, my Pi wasn't reaching the internet any more. I fixed this by creating a script to set the default gateway for the Wifi adapter when the wired adapter comes up:
sudo nano /etc/network/if-up.d/wlan0defgateway
and adding the following:
#!/bin/sh 
if [ "$IFACE" = "eth0" ]; then  
  route add default gw 192.168.0.1 dev wlan0 
fi
then set permissions using:
sudo chmod 755 /etc/network/if-up.d/wlan0defgateway
 Next you need to enable IP forwarding by editing /etc/sysctl.conf using:
sudo nano /etc/sysctl.conf
Uncomment the line “net.ipv4.ip_forward=1” and save the file.

Finally setup iptables using:
sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
Then save the iptables rules. I couldn’t save straight to /etc so I saved it in ~ and then moved it to /etc using:
sudo iptables-save > iptables.up.rules
sudo mv iptables.up.rules /etc

Create a script to restore the rules using:
sudo nano /etc/init/iptables.conf
And paste in:
# Restore iptables rules on boot 
start on (started dbus and started mountall) 
stop on (xbmc-do-stop or runlevel [!2345])  
exec iptables-restore < /etc/iptables.up.rules
Now restart the Pi and plug an Ethernet cable into the Pi and the other end into something else (I used a laptop for testing). Then set a static IP in the same range on the something else such as:
IP: 192.168.1.2
Netmask: 255.255.255.0 
Gateway: 192.168.1.1
DNS: 8.8.8.8 

Update:
I've noticed that the Pi doesn't keep its IP address recently (I'm not sure if a change in a recent release of RaspBMC caused this). I was able to fix it by editing the NetworkManager config file for the wired interface:
sudo nano "/etc/NetworkManager/system-connections/Wired connection 1"
And setting the IP address:
[ipv4]
method=manual
dns=8.8.8.8;
addresses1=192.168.1.1;24;192.168.1.1;
I then restarted NetworkManager with:
sudo service network-manager restart 
 

Sunday 9 June 2013

jQuery Sliding Pages

I wanted a series of HTML pages to act like a wizard where they would slide in and out. The show and hide methods of jQuery provide a nice animation using slide but the key was to have each content div be a fixed size with absolute positioning. This places each content div behind the previous one allowing them to appear to slide to the next. 

Here's the code:

Saturday 2 February 2013

SharePoint 2013 Site Level Ribbon Tabs

There are plenty of examples of adding a custom SharePoint ribbon tab to a list but very few examples of adding a custom ribbon tab to a site. 

If you want to add a custom ribbon tab to a site it requires custom code for the tab to be displayed (SPRibbon.MakeTabAvailable). Enabling buttons on the tab requires some JavaScript which reports that the buttons are enabled when queried.

I came across this example to add a contextual tab when a webpart is selected but I wanted the tab to always be visible. I've adapted the example for a standard (not contextual) tab which is displayed on a site when a webpart is added to the page. I've also changed the tab XML so that it is deployed as a feature rather than being declared in code.

  1. Open Visual Studio 2012 and create a new SharePoint 2013 Visual Web Part project.
  2. Name it something like CustomTabWebPart and select Farm Solution when prompted. 
  3. From Solution Explorer, right click on the project (CustomTabWebPart) and add a new item.
  4. Select Empty Element from the SharePoint templates and name it something like CustomTab.
  5. Paste the following into Elements.xml:
  6. From Solution Explorer, right click on the project (CustomTabWebPart) and add a new item.
  7. Select Module from the SharePoint templates and name it something like CustomTabJavascript.
  8. Delete the elements.xml and sample.txt files created for the module in Solution Explorer.
  9. Right click on the module (CustomTabJavascript) in Solution Explorer and add a new item.
  10. From the Web templates select JavaScript file and call it something like CustomTab.js.
  11. Past the following into the JavaScript file:
  12. Right click on the JavaScript (CustomTab.js) file in Solution Explorer, change the Deployment Type to RootFile and the Deployment Location path to Template\Layouts.
  13. Add a reference for the project to Microsoft.Web.CommandUI.
  14. Open the visual webpart’s .ascx.cs file and add the following using statements:
  15. Add the following to the same file:
  16. Add the following to the Page_Load method in the same file:
  17. Deploy the solution and add the webpart to a page. You should now see the My Tab tab on the page with a Hello World button which displays an alert when clicked.


If you want to make the button a bit more useful and launch an application page, you can do so by changing the alert in the JavaScript file to something like SP.UI.ModalDialog.showModalDialog. See the MSDN page for more details.

Its worth noting that Internet Explorer has a habit of caching JavaScript files so you might need to delete the file from your temporary internet files if changes aren't taking effect.

Tuesday 15 January 2013

SharePoint 2013 - Unexpected response from server. The status code of response is '0'. The status text of response is ''.


I was receiving this error when attempting to use the Content Search WebPart in SharePoint 2013. After pulling plenty of hair out I opened the developer tools in internet explorer (F12) and started a network capture. This showed that it was trying to reach /_vti_bin/client.svc/ProcessQuery which was getting redirected to /_login which was getting redirected to /_windows and finally back to _/vti_bin/client.svc/ProcessQuery. This repeated several times before aborting.

I then tried to reach _vti_bin/Client.svc/lists in the browser which should have returned a list of lists from the web services, but it showed the same in the network capture.

It occurred to me that the web services (client.svc) probably didn’t think I was authenticated and so were maybe redirecting me to login. The login page presumably knew I was already logged in and was redirecting me back again.

In the end I was able to fix this by enabling Anonymous Authentication for the site in IIS Manager. I need to look into the implications of having anonymous authentication enabled, but at least it showed that the problem was due to security settings.

Sunday 13 January 2013

HTML5 Storage

The HTML5 specification introduces some options for storing data on the client side. This can be either through session storage which retains the data while the browser is open or local storage which retains the data after the browser is closed.

It is worth noting that HTML5 storage data is stored unencrypted and is accessible to anything from the same domain. While I was able to play with HTML5 storage in Chrome using a local file, this didn't work with Internet Explorer 9 and it appears that it will only work with IE9 when being pulled from a web server.

You can check if HTML5 storage is supported by the client's browser with the following:

Simple data can be stored and retrieved in the following way:

Complex data types can be stored and retrieved by converting them to a string before storing using JSON.stringify() and then converting them back using JSON.parse():

I put together a quick demo using HTML5 local storage to create a phone book that supports adding, editing and deleting. It can be found here.