Tuesday, 9 December 2014

Sharepoint 2010 FAST Search: Fast Query Language lessons learned

I am currently experiencing the joys of writing FQL search queries. It has been pretty much smooth sailing after I added my Managed Properties (with this script) and using these references:

http://msdn.microsoft.com/en-us/library/office/ff394606(v=office.14).aspx
http://blogs.perficient.com/microsoft/2011/06/using-fql-to-query-fast-search-index/

However, I learned the following lessons (the hard way):

1. using 'Path' to filter by URL did not work for me. I had to use
path:starts-with("http://my-url/my-site")

2. date range queries work much better when dates are set in UTC
myDateField:range(2000-01-01T00:00:00Z, 2020-01-01T00:00:00Z)

SharePoint 2010 FAST Search: How do I create Managed Properties?

I have delving into the wonders of FAST Search and found this very helpful script to create managed properties.

It definitely saved my a lot of time and headaches. Thank you Ivan Josipovic.

Here is a copied version of the text:

function New-FASTManagedProperty([string]$Name, [string]$CrawledPropertyName, [string]$Type,[bool]$Refinement,$Sortable)
{
if ( (Get-PSSnapin -Name Microsoft.FASTSearch.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{  
 Add-PsSnapin Microsoft.FASTSearch.PowerShell
}

    switch ($Type)
    {
        "Text" {$type = "1"}  #variant 31
        "Integer" {$type = "2"} #variant 3
        "Decimal" {$type = "5"} #variant 5
        "DateTime" {$type = "6"} #variant 64
        "Float" {$type = "4"} #variant 5 ?
        "Binary" {$type = "3"}  #variant 11
    }
    $managedproperty = Get-FASTSearchMetadataManagedProperty –Name $Name
   
    if ($managedproperty -eq $null){
        New-FASTSearchMetadataManagedProperty -Name $Name -Type $Type -ea 0
        $managedproperty = Get-FASTSearchMetadataManagedProperty –Name $Name
    }

    Set-FASTSearchMetadataManagedProperty –Name $Name –Queryable $true –StemmingEnabled $false –RefinementEnabled  $Refinement -SortableType $Sortable

    $cp = Get-FASTSearchMetadataCrawledProperty -Name $CrawledPropertyName
        if ($cp -eq $null){
            switch($type){
                "1" {$variant = "31"}  #Text 31
                "2" {$variant = "3"} #Integer 3
                "5" {$variant = "4"} #Decimal 5
                "6" {$variant = "64"} #DateTime 64
                "4" {$variant = "5"} #Float 5 ?
                "3" {$variant = "11"}  #Binary 11
            }
            New-FASTSearchMetadataCrawledProperty -Name $CrawledPropertyName -Propset "00130329-0000-0130-c000-000000131346" -VariantType $variant
            $cp = Get-FASTSearchMetadataCrawledProperty -Name $CrawledPropertyName
            write-host "Created $($CrawledPropertyName) Crawled Property"
        }

$property = Get-FASTSearchMetadataCrawledPropertyMapping -name $Name

if ($property -ne $null)
{
Remove-FASTSearchMetadataCrawledPropertyMapping –managedproperty $managedproperty -crawledproperty $cp -force
}

        New-FASTSearchMetadataCrawledPropertyMapping –Managedproperty $managedproperty –crawledproperty $cp -ea 0
           
       
    write-host "Created $($Name)"
}

It can be invoked as follows:

New-FASTManagedProperty "ListItemID" "ows_id" "Integer" $true "1"  

Monday, 1 December 2014

Cntlm: No connection could be made because the target machine actively refused it 127.0.0.1:3128

Cntlm is a great tool to create an internet proxy. I wrote about how to configure it here.  However, I recently encountered the following error message when trying to access a local REST service:

No connection could be made because the target machine actively refused it 127.0.0.1:3128

The port number rang a mental bell as it was configured as the listening port for Cntlm. I deactivated Cntlm:

1. Stopped the windows service
2. Reverted the proxy settings in my browser

No luck.

I tried rebooting the server, but that did not resolve the problem.

More investigation revealed that Application Pool account for my custom web site was caching the Cntlm connection. I connected to the machine as the Application Pool account and noticed that the proxy settings for cntlm where still there. I was able to reset the settings to resolve the problem.

Alternatively, I could change the Application Pool account.

Wednesday, 19 November 2014

SharePoint Online: How do I set the Web.AlternateCSS property in CSOM?

The properties are only exposed in the '16' (SharePoint Online) version of the client side dlls. You will need to change your references to point to

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll

and

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll

Tuesday, 18 November 2014

C#: How do I store a secure password?

The eternal problems of encryption and data security is an ever present headache for all developers.
This post provides a great introduction to the problem.

Fortunately, C# provides a very powerful Windows Data Protection API to resolve this issue.

Read more about it here and find the sample code here.

Here is a simple extension method to achieve the required result:

using System;
using System.Security.Cryptography;
using System.Text;

namespace MyProject.Security
{
 public static class SecurityExtensions
    {
        private const DataProtectionScope Scope = DataProtectionScope.CurrentUser;
        static readonly byte[] AdditionalEntropy = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };

        public static string Encrypt(this string plainText)
        {
            if (plainText == null) throw new ArgumentNullException("plainText");

            var data = Encoding.Unicode.GetBytes(plainText);
            var encrypted = ProtectedData.Protect(data, AdditionalEntropy, Scope);

            return Convert.ToBase64String(encrypted);
        }

        public static string Decrypt(this string cipher)
        {
            if (cipher == null) throw new ArgumentNullException("cipher");

            var data = Convert.FromBase64String(cipher);

            var decrypted = ProtectedData.Unprotect(data, AdditionalEntropy, Scope);
            return Encoding.Unicode.GetString(decrypted);
        }
    }
}

The usage would be as follows:

var plainPassword = "MyPassword";
var encryptedPassword = plainPassword.Encrypt();
var plainPasswordAgain = encryptedPassword.Decrypt();

This can also be moved to a PowerShell script:

namespace MyProject.Security
{
    // This class is used by the EncryptionHelper class to expose the encryptions methods

    public class SecurityHelper
    {
        public static string Encrypt(string plainText)
        {
            return plainText.Encrypt();
        }

        public static string Decrypt(string cipher)
        {
            return cipher.Decrypt();
        }
    }
}

function Get-EncryptedPassword
{        
[CmdletBinding()]        
Param(        
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]        
[string]$PlainPassword,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]        
[string]$DllDirectory
)    

$bytesCommon = [System.IO.File]::ReadAllBytes("$DllDirectory\MyProject.Security.dll")
$loadResultCommon = [System.Reflection.Assembly]::Load($bytesCommon)

return [MyProject.Security.SecurityHelper]::Encrypt($PlainPassword)
}

function Get-DecryptedPassword
{        
[CmdletBinding()]        
Param(        
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]        
[string]$EncryptedPassword,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]        
[string]$DllDirectory
)    

$bytesCommon = [System.IO.File]::ReadAllBytes("$DllDirectory\MyProject.Security.dll")
$loadResultCommon = [System.Reflection.Assembly]::Load($bytesCommon)

return [MyProject.Security.SecurityHelper]::Decrypt($EncryptedPassword)
}

This would be invoked as:

# get the directory of the dll.
$dir = Get-Location
# include the commandlets so they can be used
. .\<scriptName>.ps1
$cipher = Get-EncryptedPassword("P@$$W0rD")
$plainText = Get-EncryptedPassword($cipher)

Wednesday, 5 November 2014

C#: How do I generate a SecureString password?

There is a simple function to generate a secure string password:

            public static SecureString StringToSecure(string password)
            {
                var secure = new SecureString();
                foreach (char c in password)
                {
                    secure.AppendChar(c);
                }
                return secure;
            }

Tuesday, 4 November 2014

SharePoint Online: How do I brand my Sites, Subsites and OneDrive for Business Site?

The patterns for applying branding during site creation have changed, but fortunately, the Patterns and Practices team have provided some excellent guidance on how to resolve some common issues.

Here are some of the links I have found very useful:

Async site collection creation:

Sub site creation app:

OneDrive for Business:
https://github.com/OfficeDev/PnP/tree/master/Solutions/Provisioning.OneDrive

Thursday, 16 October 2014

How do I create a internet proxy for an account that does not have internet access?

The development domain for my current client does not given its account internet access. Thi can be overcome in Powershell scripts as follows:

$user = "MyDomain\MyAccount"

$password = ConvertTo-SecureString –String "password" –AsPlainText -Force
$cred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $user, $password

[System.Net.WebRequest]::DefaultWebProxy.Credentials = $cred

but it becomes a problem is the current user credential is used do download files or if the proxy server blocks certain actions. A fantastic tool to resolve this problem is cntlm, which allows you create a local internet proxy.

The configuration (simplified) is as follows:

1. Download and install the software.
2. Set the username and domain in the .ini file. Remove the password setting
3. Type the Url of internet proxy.pac file in a browser and get proxy urls. Add these urls to the config file and remove the 'sample' entries.
4. Execute 'cntlm -M http://www.google.com' and get the authentication type. Copy the Auth and Password to the configuration file.
5. Remove/uncheck the 'Automatic configuration' settings and update the proxy in the browser to point to localhost 3128 (which is configured as the listen port)

6. Close existing browsers and restart the windows service.

You should be good to go.

SharePoint: How do I find out (quickly) if my server has a Kerberos ticket?

A new SharePoint project introduced the prospect of the dreaded 'double hop' problem and the team was looking at ways to resolve the issue. Naturally, Kerberos (and delegation) was the natural solution. However, we were not sure if the Farm and Servers had Kerberos enabled.

A quick one word line command resolved the problem: klink.

This command displays a list of currently cached Kerberos tickets.

Monday, 13 October 2014

PowerShell: How do I know what methods a commandlet has?

There is nothing more frustrating than trying to find out what methods are exposed in a commandlet that you are using. Fortunately, there is a commandlet to expose commandlets:

Get-Member

So, if I wanted to know what properties / methods are exposed in Get-SPOSite, I would execute the following:

Get-SPOSite | Get-Member


Thursday, 2 October 2014

MVC4: Why cant I resolve the WebSecurity class?

While trying to create a two step password reset page, I struggled to find the required reference for the WebSecurity class (to generate the ResetToken).

The solution is to add a reference to
C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v2.0\Assemblies\WebMatrix.WebData.dll

Wednesday, 1 October 2014

C#: Compare two text files (quickly)

I am busy writing a windows service that is send emails. However, I need to track the emails that have already been sent to that people. The current solution writes the audit to a text file (SQL Server is not an option).

I hit a major performance problem when processing a 30000 row file - I had already processed 5000 records and the iterative (line by line) approach was just not working. I put my SQL hat on and looked for a C# equivalent of the EXCEPT command.

Enter Googles Diff Match Patch.

It has a simple C# class that performs incredibly well. I now has a very simple and fast solution.

Here is the code:

using DiffMatchPatch;

string source;
string target;

// Load the source file into a string
using (StreamReader  reader = new StreamReader(MYSOURCEFILE))
{
  source = reader.ReadToEnd();
}

// Load the comparison file into a string
using (StreamReader  reader = new StreamReader(MYTARGETFILE))
{
  target = reader.ReadToEnd();
}

// Instantiate the class
var comparisonClass = new diff_match_patch();

// Perform the comparison
var diffs = comparisonClass.diff_main(source, target, true);

// Find all new items
var newRecords = diffs.FindAll(x => x.operation.ToString() == "INSERT");

I can now iterate through the new records and process them as required.

foreach (var newRecord in newRecords)
{
 // Insert magic here...
}




Thursday, 25 September 2014

SQL Server Scripts: Restart the SQL Service through a batch file

My SQL instance also has a tendency to consume all the memory on the VM (even 16GB is not enough), so I keep another script on the desktop to restart the SQL.

My first problem was finding the name of the service. A simple 'net start' command in the command prompt listed all the services.

The following script solved my problem:

ECHO "Stopping SQL Server"
net stop "MSSQLSERVER" /Y
ECHO "Starting SQL Server"
net start "MSSQLSERVER"
@PAUSE

I have found this to be very helpful when the machine is struggling and opening up services.msc seems to take an eternity.

I have rekindled my love of batch files - they certainly solve the problem quickly and efficiently.


Tuesday, 23 September 2014

PowerShell: How do I remove a module by force?

I recently added a module to my PowerShell  version and things (to put it mildly) did not go well.

I tried using Remove-Module but that also failed. I ended by bypassing tact and using a sledgehammer.

I navigated to My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
and removed the module entry manually.



Thursday, 11 September 2014

SharePoint 2010: Why cant I deploy my timer job to the specific Web Application?

Writing a timer service is easy ans there are many examples available. However, while following the instructions I encountered several problems deploying the job to a single web application.

I followed the basic instructions (set the feature scope to WebApplication and the 'Assembly Deployment Target' to GlobalAssemblyCache) but the timer job was being activated across all web applications.

Here is how I resolved it:
1. Set the project property 'Include Assembly In Package' to false. This removes the 'Assembly Deployment Target' option.
2. Add the output assembly as an 'Additional Assembly' in the 'Advanced' section of the package manifest.
3. Change the 'Activate on Default' in the feature properties to false.

The feature will be deployed to the Web Application, but not activated. Use PowerShell to activate it.

SharePoint Online: How do I set the IRM settings for a Document Library in PowerShell?

I have used the CSOM approach to resolve the problem.

Here is an excellent post outlining the available methods that I based this script on.

Import-Module 'C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell' -DisableNameChecking

$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

$webUrl = "https://mytestsite.sharepoint.com/mysubsite"
$username = "richard.leeman@mysharepointonlinelogin.com"
$password = Read-Host -Prompt "Password for $username" -AsSecureString

$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webUrl)
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
$web = $ctx.Web
$lists = $web.Lists

$ctx.Load($lists)
$ctx.Load($web)
$ctx.ExecuteQuery()

$list = $lists| Where-Object { $_.Title -eq "My Document Library"}

#enable permissions on the library
$list.IrmEnabled = $true
#title
$list.InformationRightsManagementSettings.PolicyTitle = "My title"
# description
$list.InformationRightsManagementSettings.PolicyDescription = "My description"
# reject items that do not support IRM
$list.IrmReject = $true
# expire the restriction
$list.IrmExpire = $true
$list.InformationRightsManagementSettings.DocumentLibraryProtectionExpireDate = "10/15/2015"
# disable opening documents in the browser
$list.InformationRightsManagementSettings.DisableDocumentBrowserView = $true
# allow users to print
$list.InformationRightsManagementSettings.AllowPrint = $true
# allow script script and screen reader functions to downloaded documents
$list.InformationRightsManagementSettings.AllowScript = $true
# allow viewers to write a copy of the downloaded documents
$list.InformationRightsManagementSettings.AllowWriteCopy = $true
# access rights expiry
$list.InformationRightsManagementSettings.EnableDocumentAccessExpire = $true
$list.InformationRightsManagementSettings.DocumentAccessExpireDays = "2" # between 1 and 365
# require credential verification
$list.InformationRightsManagementSettings.EnableLicenseCacheExpire = $true
$list.InformationRightsManagementSettings.LicenseCacheExpireDays = "4"
# Allow group protection
$list.InformationRightsManagementSettings.EnableGroupProtection = $true

$list.Update()
$ctx.ExecuteQuery()


Tuesday, 26 August 2014

SPQuery returning error "One or more field types are not installed properly. Go to the list settings page to delete these field"

A recent Caml Query was returning the follow error: One or more fields are not installed properly.

The most likely cause of the problem is that the internal names are not correct in the query. However, this was not the cause. The culprit was my very extensive column naming convention which was more than 32 characters long. It seems that the name was being truncated in the query.

A quick rename of the column resolved the problem.

Tuesday, 12 August 2014

WCF: A binding instance has already been associated to listen URI http://site/_vti_bin/restservice.svc

The simple resolution to this was to change my endpoint address to a relative url.

The endpoint address was set as an empty string

<endpoint address=""
  binding="basicHttpBinding"
  contract="MyNamespace.IMyContract" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>

I changed the address to the relative path (_vti_bin/Folder/MyService.svc) to resolve the problem.

Thursday, 31 July 2014

JQuery-Upload: unexpected token

While working with the JQuery-Upload control, I encountered the following error:

unexpected token <

The real kicker was the fact that my target file was still being created.

The cause of the problem (as I eventually discovered) was my REST contract; my endpoint as configured as follows:

[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.WrappedResponse,
UriTemplate = "/file/upload")]
StatusData Upload(Stream fileData);

but my endpoint was returning a JSON response.

This resulted in a mismatch, as the expected response format was XML.

Changing the contract to Json resolved the problem.

Wednesday, 30 July 2014

JQuery-Upload - a few ways to upload a file

I was recently using the magnificent jQuery-File-Upload in a SharePoint 2010 application. I encountered the following scenarios to upload files.

1. Load immediately when the file is selected
This is the easiest option and is pretty much OOTB.
$('#fileupload').fileupload({
                dataType: 'json',
                headers: {
                    Accept: "application/json"
                },
                accept: 'application/json',
                formData: {
                    url: "http://mytargetlocation",
                    title: "myTitle"
                },
                done: function (e, data) {
                    success();
                }
            });

2. Defer load until a button is checked
This code will attach the 'submit' processing to the click event of a button with the ID 'btnSave'

<input id="btnSave" type="submit" >

 $('#fileupload').fileupload({
                dataType: 'json',
                headers: {
                    Accept: "application/json"
                },
                accept: 'application/json',
                formData: {
                    url: "http://mytargetlocation",
                    title: "myTitle"
                },
                add: function (e, data) {
                    data.context = $('#btnSave')
                        .click(function () {
                            data.submit();
                        });
                },
                done: function (e, data) {
                    success();
                }
            });

This approach is great if you are ready for a full postback when the button is clicked.

3. Defer load and load the file in code
This code puts the file in an array, which is used in the 'uploadFile' method to push it to SharePoint

I used this great posting on StackOverflow to find this solution.

var myfiles = [];

 $('#fileupload').fileupload({
                dataType: 'json',
                headers: {
                    Accept: "application/json"
                },
                accept: 'application/json',
                formData: {
                    url: "http://mytargetlocation",
                    title: "myTitle"
                },
                add: function (e, data) {
                    $.each(data.files, function (idx, file) {
                        myfiles.push(file);
                    });
                },
                done: function (e, data) {
                    success();
                }
            });

        function uploadFile() {
            var file = myfiles.pop();
            $('#fileupload').fileupload('send', { files: [file] });
}

Thursday, 10 July 2014

Powershell: How do I execute a script in a new Powershell instance?

The great thing about PS is that is caches its objects for reuse. The bad thing about PS is that is caches its objects for reuse. Sometimes, scripts need to be executed in their own PS instances in order to avoid any changed data.

Here is a simple example of a wrapper script (wrapper.ps1) that executes another script (test.ps1) in the same folder. The test script open notepad with the SchemaXml of a document library.

Wrapper.ps1:
function Get-ScriptDirectory 
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value 
 Split-Path $Invocation.MyCommand.Path 

$dir = Get-ScriptDirectory
cd "$dir"

powershell.exe "& `"$dir\test.ps1`" "

Test.ps1:
function AddSharePointSnapin([bool] $addSnapin)
{
    $sharePointSnapinName = "Microsoft.SharePoint.PowerShell"
    If ($addSnapin)
    {
        Write-Host "Adding $sharePointSnapinName Snapin ..."
        Add-PSSnapin $sharePointSnapinName -ErrorAction SilentlyContinue
    }
    Else
    {
        Write-Host "Removing $sharePointSnapinName Snapin ..."
        Remove-PSSnapin $sharePointSnapinName -ErrorAction SilentlyContinue
    }
}

AddSharePointSnapin $true

$fileName = "doclib.txt"
$web = Get-SPWeb "http://docreval.in.telstra.com.au"
$list = $web.Lists["Documents"]
$list.SchemaXml > $fileName 
Start-Process notepad  -ArgumentList $fileName

Wednesday, 9 July 2014

Powershell; Write a file and open it

I have found this code quite helpful in debugging - especially trying to look through a large xml schema file for a SharePoint list.

$fileName = "myFile.txt"

# Write some variable property to a file
$web = Get-SPWeb "http://blah.com"
$list = $web.Lists["My List"]
$list.SchemaXml > $fileName

# Open the file in notepad
 Start-Process notepad  -ArgumentList $fileName

Monday, 7 July 2014

SharePoint 2010: No item exists at http://site?ID=1. It has be been deleted by another user.

What the heck? I added a query string parameter to pass a value to a REST API and my solution exploded. Fortunately, there is a simple solution provided by our friends at Microsoft (see here).

It seems that the querystring parameter 'ID' is reserved, so renaming it to something else (in my case, docid) resolved the problem.

Wednesday, 2 July 2014

PowerShell: How do I run a Timer Service job?

This is an easy one liner:

Get-SPTimerJob | Where-Object { $_.Name -like "*My Timer Service*" } | Start-SPTimerJob

Tuesday, 24 June 2014

SharePoint 2010: Why does my RunWithElevatedPrivileges not pick up the context of the Application Pool user?

It is important to remember that RunWithElevatedPrivileges requires its own SPWeb. If you reuse a existing SPWeb, you won't run elevated, but with the initial context.

For Example, the following function is intended to perform some actions on the sub sites for the given site. The access requires elevated permissions:

This function will not work:

private void DoStuff (SPWeb web)
{
SPSecurity.RunWithElevatedPrivileges(() =>
{
foreach (SPWeb w in web.Webs)
// Still running under logged in user credential
}
});
}

but this will:

private void DoStuffProperly(SPWeb web)
{
SPSecurity.RunWithElevatedPrivileges(() =>
{
using (SPSite site = new SPSite(web.Url))
{
using (SPWeb w = site.OpenWeb())
{
// Running under the application pool credential
}
}
});
}

Thursday, 19 June 2014

SharePoint 2010: Why is my name displaying as DOMAIN\LOGIN instead of Displayname?

My development environment was displaying my name as 'DOMAIN\LOGIN' instead of 'DisplayName'. I found the solution in this post - a simple one-line PowerShell command:

Get-SPUser -Web http://myweb.com | Set-SPUser -SyncFromAD

Monday, 9 June 2014

SharePoint 2010: How do I load a picture and meta data to an asset library?

I recently had to load some seed data for a SharePoint site that required the population of some images into an asset library. After a lot of playing and experimenting, I eventually settled on the pattern of

1. Add the files to an image folder in the Style Library
2. Reading in the source file into a byte array
3. then loading the array into a new file in the target location.

Its a little convoluted, but it was the only solution that met my requirement.

I then populated a dictionary with a name/value pair that mapped to the columns in my content type.

Here are the methods I used:

     public void UploadFile(SPWeb webParam, string fileUrl, SPList list, Dictionary<string, string> parameters)
        {
            try
            {
             
                using (SPSite site = new SPSite(webParam.Url))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        //SPList list = web.Lists.TryGetList(listName);

                        string urlOfFile = string.Format("{0}/{1}", list.RootFolder.ServerRelativeUrl, Path.GetFileName(fileUrl));
                        string title = Path.GetFileName(fileUrl).Substring(0, Path.GetFileName(fileUrl).IndexOf("."));

                        using (Stream file = (new WebClient() { Credentials = CredentialCache.DefaultCredentials }).OpenRead(fileUrl))
                        {
                            byte[] b = ReadFully(file);

                            using (MemoryStream DocumentStream = new MemoryStream())
                            {
                                using (StreamWriter writer = new StreamWriter(DocumentStream))
                                {
                                    writer.Write(b);
                                    writer.Flush();
                                    SPFile file2 = list.RootFolder.Files.Add(Path.GetFileName(fileUrl), DocumentStream, true);
                                    file2.Update();
                                    list.Update();
                                }
                            }
                        }

                        SPListItem uploadedFile = web.GetListItem(urlOfFile);
                        if (uploadedFile != null)
                        {
                            // for the hyperlink
                            SPFieldUrlValue urlValue = new SPFieldUrlValue();
                            urlValue.Description = title;
                            urlValue.Url = fileUrl;
                            uploadedFile["AlternateThumbnailUrl"] = urlValue;

                            foreach (var i in parameters)
                            {
                                uploadedFile[i.Key] = i.Value;
                            }

                            uploadedFile.Update();
                        }
                        else throw new Exception("Something bad happened!");
                    }
                }

            }
            catch (Exception ex)
            {
                // handle exception here
            }
        }

        public static byte[] ReadFully(Stream input)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }

And here is the invocation:

string sourceFile = "http://SiteCollection/Site/Style%20Library/myimage.png";

Dictionary<string, string> parameters = new Dictionary<string,string>();
parameters.Add("Title", "My Test Title");
parameters.Add("MyCustomColumn", "Foo");

UploadFile(web, sourceFile, web.Lists["MyList"], parameters);

Sunday, 25 May 2014

SharePoint 2010: How do I populate a lookup field in C#?

I had the requirement to populate seeddata in a simple list structure that contained some lookup columns. The lookup requires the identifier/display text of the source object - in my case it was a ParentItem that was being used in the ChildItem table. I created a lookup column 'Parent' and added it the child list.

The following code resolved the problem.
Please note that this code is for seed data that has expected values and does no validation checking or use any defensive programming.

// Add items to the parent item
SPList parentList = web.Lists["ParentItem"];
SPListItem item = parentList.Items.Add();
item["Title"] = "Parent Header 1";
item.Update();

// Add the child item
SPList childList = web.Lists["ChildItem"];
item = childList.Items.Add();

SPListItem parentItem = GetHeaderItem(parentList, "Parent Header 1");

item["Title"] = "My Child Item";
item["Parent"] = new SPFieldLookupValue(parentItem.ID, parentItem.Title);
item.Update();

private SPListItem GetParentItem(SPList list, string title)
{
SPQuery query = new SPQuery()
{
Query = string.Format("<Where> <Eq> <FieldRef Name=\"Title\"></FieldRef> <Value Type=\"Text\">{0}</Value> </Eq> </Where>", title)
};

SPListItemCollection items = list.GetItems(query);
if (items.Count > 0)
{
return items[0];
}
else
{
return null;
}
}



Tuesday, 13 May 2014

SharePoint 2007: .asmx was not recognized as a known document type.

I am interfacing with a SharePoint 2007 farm via web service. I tried adding the _vti_bin/webs.asmx as a service reference when the following error:

The document at the url http://blah.com/_vti_bin/webs.asmx was not recognized as a known document type.

Fortunately, there is a simple solution to the problem: add ?wsdl to the url and the problem is resolved.

Sunday, 4 May 2014

AngularJS: How do I render HTML in an ng-repeat?

Rendering HTML with Angular should be a simple task - ng-bind-html should do the trick. (see here).

However, I was struggling to do the same thing in an 'ng-repeat'. I tried using $sanitize, but that did not work. Eventually, I found the solution on stackoverflow: instead of having the iteration sitting above the rendering, one can consolidate the two to produce the required result.

So
                <span ng-repeat="item in items" me-update-flexslider="y">
   <span class="ng-bind-html:{{item}}"></span>
                </span>
became

                <span ng:repeat="item in items" ng-bind-html="item"></span>

Tuesday, 22 April 2014

SharePoint 2010: Add an Event Receiver in code

Some requirements demand the adding of Event Receivers in code and not as features. Fortunately, there is a simple method to perform this task.

The following code adds an 'ItemAdding' event receiver in the class 'MyEventReceiver'. The project namespace is 'MyProject'

using (SPSite site = new SPSite("http://blah.com"))
{
   using (SPWeb web = site.OpenWeb())
   {
      SPList list = web.Lists["MyList"];
      list.EventReceivers.Add(SPEventReceiverType.ItemAdding, Assembly.GetExecutingAssembly().FullName, "MyProject.MyEventReceiver");
   }
}




SharePoint 2010: How can I change my Date column to display only the date (DateOnly)?

I thought this would be a piece of cake - open up SharePoint Manager, get the XML and done. Unfortunately, that is not the case. The property DisplayFormat holds the value, and the XML produced seems fine but the field kept on displaying the time.

I then saw this article from Microsoft with the answer - the XML element is Format, NOT DISPLAYFORMAT.

Adding Format="DateOnly" to my field XML resolved the problem.

Tuesday, 15 April 2014

SharePoint 2010: How I can stop the timeout when I am debugging server side code in Powershell?

Debugging code can be frustrating at times - even more so when your attachment to the w3wp.exe times out. A simple solution to the problem is to disable the 'Ping' on the application pool. This is accessed through the 'Advanced Settings'.


Alternative, if you are lazy like me, you can run the following PowerShell script to disable it on all web applications:

Get-WmiObject -Class IISApplicationPoolSetting -Namespace "root\microsoftiisv2" | ForEach-Object { $_.IdleTimeout=0; $_.PingingEnabled=$false;  $_.Put(); }


Monday, 14 April 2014

SharePoint 2010: AllowEveryoneViewItems

A blog I received from Ishai Sagi's blog SharePoint Tips and Tricks highlighted a SPList property that I was not aware of: AllowEveryoneViewItems.

It seems that this property allows you to overwrite the item permissions for access to a document or list attachment, regardless of the other permissions. See more here.


Thursday, 10 April 2014

Windows Server 2008 R2: Group Policy changes for a better RDP and Development environment experience

My development VM is running off Windows Server 2008 R2. Some of the default settings are not conducive to easy development, so I made the following changes to make my life easier:

1.       Turn off User Access Control (see here)
2.       Make the following Group Policy changes (go to gpedit.msc > Computer Configuration > Adminstrative Templates> Windows Compopnents > Remote Desktop Services > Remote Desktop Session Host)
a.       > Session Time Limits > Set time limit for disconnected sessions  > Disable
b.      > Session Time Limits > Set time limit for active but idle Remote Desktop sessions  > Disable
c.       > Device & Resource Redirection > Do not allow clipboard > Disable
3.       Move page file to another drive if your running out of space on C: (see here)
4.  Remove the automatic log-off settings (see here)

Wednesday, 9 April 2014

SharePoint 2010: Why is my new inline style not being rendered through the SharePoint client object model?

My page has a DIV that needs to be hidden based on some runtime logic. I was running my code after the page loaded,

 SP.SOD.executeOrDelayUntilScriptLoaded(function () {
        hideMyStuff($data);
    }, "SP.js");

My function 'hideMyStuff' called another function to handle the hiding logic. My hiding code was simple:

function hideDIV(divId)
{
    document.getElementById(divId).style.display = 'none';
}

That should work, but nothing was happening. On further inspection, I noticed that the CSS class in the page was using a lot of '!important' with its CSS settings, which was overriding my code.

This left 2 options to resolve the problem:

1. Sledgehammer approach: set the value with !important.
The method would become
    document.getElementById(divId).style.display = 'none!important';

2. Stylish approach:  add a new class to the DIV at runtime.
The class is simple:
.hidden {
    display:none;
}

and the hide method (using JQuery) becomes:
 $("#" + divId).addClass('hidden');

Tuesday, 8 April 2014

SharePoint 2010: Error code 12031 in WCF Endpoint called from the Client Object Model

I created a simple WCF endpoint to reference a REST service to return data from the client object model. All was going well until a single test account started to fail. One would work, another would fail.

I found the answer here.

Once of the scenarios in the code was not setting a DateTime property in the DataContract class.

I changed the code to set the value of the field to DateTime.MaxValue to resolve the problem.

How do I enable my clipboard when I remote into a Windows Server 2008 R2 VM?

Not being able to cut and paste between a host PC and a VM is more than a little irritating. The problem is a group policy that, by default, disables this functionality. To enable it.

1. Edit the VMs Group Policy



2. Set the 'Do Not Allow Clipboard Redirection' to Disabled


3. Reboot the machine for the changes to take effect.

Thursday, 3 April 2014

How do I set my username and password for Mercurial (no more prompting please)?

My new project uses Mercurial as the source control. The daily pull of data becomes a little tedious when you are constantly prompted for credentials. I have add a few simple settings to resolve the (annoying) problem.

Open the workbench, right click on the repository and select settings. The name of the settings file is displayed at the top of the repository settings page.

My location was c:\MyProject\.hg\hgrc

Now, open this file in your favourite text editor and add a few simple entries:

[ui]
username=Richard Leeman <richard@leeman.com>

[auth]
repo.prefix=http://myrepositorylocation/code
repo.username=Richard Leeman
repo.password=P@$$w0rd

This is not the most secure way to store the credentials, but it certainly beats having to enter them every time.


Monday, 17 February 2014

LINQ: How can I do a 'contains' on an integer field?

I was trying to write a LINQ query to mimic a string Contains value. The code seemed easier enough: use a lamba and use the same way you would in standard c# (x => x.Code.ToString().Contains("MySearchString").

No good. LINQ complained and I was stuck.

One workaround is to use SqlFunctions.StringConvert to convert the field.

So, my lamba became x=> SqlFunctions.StringConvert((double)e.Code).Contains("MySearchString")

Wednesday, 12 February 2014

SharePoint 2013: Configure 2013 Workflows for Sharepoint Designer

Workflows are configured a little differently in SharePoint 2013 than they are in 2010. I tried to find a good resource to take me through the installation and the best one I found was at harbar.net

A brief summation of the steps are:
1. Download workflow manager
2. Download workflow client
3. Add a binding to new web (12290 for https / 12991 for http)
4. Register the Service
5. Make sure that the port (12290/12291) is allowed as an incoming rule in the firewall.

The only problem I encountered while following the installation instructions (which are excellent) was the registration if the SPWorkflowService. I found the resolution to my problem on the Microsoft site - my Register-SPWorkflowService command needed a –AllowOAuthHttp flag at the end.


Tuesday, 4 February 2014

Visual Studio 2012: Error loading 'NuGet' when creating a new MVC project

I tried to create a new MVC 4 project in Visual Studio 2012 and was greeted with the following message:

Error: this template attempted to load component assembly 'NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. For more information on this problem and how to enable this template, please see documentation on Customizing Project Templates.

The fix is pretty simple - download and install the NuGet Package Manager from http://visualstudiogallery.msdn.microsoft.com/27077b70-9dad-4c64-adcf-c7cf6bc9970c

Monday, 3 February 2014

SharePoint 2010: Is there an easy way to manage my Forms Based Authentication users?

I recently configured a site to authenticate through Forms Based Authentication. The problem with this authentication method is that managing the users and roles is quite a pain. However, I found a FBA Pack on CodePlex, which provides a magnificent management interface.

Get it here.

SharePoint 2010: Why can I not find my FBA users in my People Picker?

I recently configured Forms Based Authentication for my site but soon found that my beloved people picker was not finding the users that I added.

The solution was to add the membership provider I used in my configuration to the PeoplePickerWildCards section of the web.config.

In my case, the following entry resolved the problem:

<add key="FBAMembershipProvider" value="%" />

SharePoint 2010: How do I configure Forms Based Authentication?

There are a number of steps required in FBA configuration, but they are well documented in this post:

http://donalconlon.wordpress.com/2010/02/23/configuring-forms-base-authentication-for-sharepoint-2010-using-iis7/

Thursday, 30 January 2014

CRM 2011: How do I validate that a text field is numeric?

I need to change the format of an ID field in CRM 2011. The system settings were inserting commas as thousands separators and this looks strange for an ID (ID 123,456 is just not right).

I recreated the field as a text field, but I needed to validate the input.I therefore created the following functions that I added to the 'onSave' list of my CRM form:

When configuring the script, ensure that 'pass context as the first parameter' is set and then pass in the name of the field to search (in double quotes).

Here is the script:

validateIDOnSave = function(executionObj, IDField)
{
    var IDFieldValue = Xrm.Page.getAttribute(IDField).getValue();

    if(IDFieldValue != null)
    {
      var IDFieldObject = Xrm.Page.ui.controls.get(IDField);

      if (isNumber(IDFieldValue ) == false)
       {
                executionObj.getEventArgs().preventDefault();
                alert("The ID must be a number");
                IDFieldObject.setFocus();
        }
    }
    else
    {
        // ID Field is null. Don't validate
    }
}

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

Thursday, 16 January 2014

MVC 4: How do I download a list as a CSV?

I added a simple link in my view

@Html.ActionLink("Export Data", "ExportData")

and a simple method in my controller to take care of the download

public ActionResult ExportData()
{
return DownloadCSV();
}

public FileContentResult DownloadCSV()
{
string csv = string.Concat(from x in db.MyData
  select x.ID + ","
  + x.Name + "\n");

return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv",  string.Format("Export.{0}.csv", DateTime.Now.ToString("yyyy-MM-dd_HHmmss")));
}

Sunday, 12 January 2014

MVC 4: How do I line-wrap my text in an editor?

The solution is to add an annotation to the field in the model class:

[DataType(DataType.MultilineText)]

Then, to display the item in the view, use Html.Raw.

@Html.Raw("<pre>"+ Html.Encode(@Model.MyField) + "</pre>"

Thursday, 9 January 2014

MVC 4: How do I generate a pdf file from a view?

I looked at several possible solutions (including itextsharp) but there were always issues rendering the CSS correctly.

Fortunately, I found the following gem in codeplex: http://pdfgenerator.codeplex.com/

I used the following code to generate the HTML from the view (sourced from here):

 public string RenderViewToString(Controller controller, string viewName, object viewData)
        {
            var renderedView = new StringBuilder();
            using (var responseWriter = new StringWriter(renderedView))
            {
                var fakeResponse = new HttpResponse(responseWriter);
                var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), controller.ControllerContext.RouteData, controller.ControllerContext.Controller);

                var oldContext = HttpContext.Current;
                HttpContext.Current = fakeContext;

                using (var viewPage = new ViewPage())
                {
                    var html = new HtmlHelper(CreateViewContext(responseWriter, fakeControllerContext), viewPage);
                    html.RenderPartial(viewName, viewData);
                    HttpContext.Current = oldContext;
                }
            }

            return renderedView.ToString();
        }

and this to generate the byte array:

byte[] buffer = (new HtmlToPdfConverter()).GeneratePdf(htmlText);

and finally, this to generate the file:

 public class BinaryContentResult : ActionResult
    {
        private readonly string contentType;
        private readonly byte[] contentBytes;

        public BinaryContentResult(byte[] contentBytes, string contentType)
        {
            this.contentBytes = contentBytes;
            this.contentType = contentType;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            var response = context.HttpContext.Response;
            response.Clear();
            response.Cache.SetCacheability(HttpCacheability.Public);
            response.ContentType = this.contentType;

            using (var stream = new MemoryStream(this.contentBytes))
            {
                stream.WriteTo(response.OutputStream);
                stream.Flush();
            }
        }
    }