Tuesday, December 20, 2016

Using Fiddler to test a POST call to a custom WCF REST service hosted in SharePoint 2013

Under Parse tab change the call type to "POST"
Content type should be set to json
In the "Request Body" specify the parameters to be sent as shown below


Fiddler Image:

To create a custom WCF REST service hosted in SharePoint 2013, follow this link

Saturday, October 29, 2016

Sending POST call to WCF REST web method - SharePoint

When it comes to SharePoint usage there are many examples in the web about REST GET calls, but not so much on POST. So here goes..

My target REST method signature is as follows

public List<Details> GetDetails(string ids)

The method declaration in the Interface is as below:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "GetDetails", BodyStyle = WebMessageBodyStyle.Wrapped,
 RequestFormat = WebMessageFormat.Json,
 ResponseFormat = WebMessageFormat.Json)]
List<Details> GetDetails(string ids);

The trick here is making the web message body style "Wrapped"

Now from the client-side you make a call to the method.
In my example I use the service invocation within a AngularJS function. You send the parameter information in the data

    $scope.TestMethod = function () {
        var endpointAddress = "http://myTestSite.com/sites/TestSite/_vti_bin/CustomService.svc";
        var callurl = endpointAddress + "/GetDetails";
        $.ajax({
                type: "POST",
                url: callurl,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                data: '{"ids": "18"}',
                success: function () {
                    alert('success');
                },
                error: function () {
    alert('error');
}
            });

    };

Friday, October 28, 2016

Passing parameter containing special characters to web service methods

Web service does not process parameters with special characters as those can be candidates to dangerous inputs.

So as a workaround you can send the parameters as a query string. That said, the query string should not be too long since there are limitations

For illustration purposes, in the below example JavaScript call I send two variables id & date as method parameters. The address information which is included in variable address1 & address2 are send as  query string.

var restUrl = _spPageContextInfo.webAbsoluteUrl +
            "/_vti_bin/MyService.svc/MyMethod/" + id + "/" + date + "?address1=" + encodeURIComponent(address1) + "&address2=" + encodeURIComponent(address2) ;

Inside your web method access the query string as below:

string address = HttpContext.Current.Request.QueryString["address1"];

Sunday, September 4, 2016

Update tags in Word document with Data using OpenXML

The objective is to replace the specified tags in a word document(.docx) using OpenXml.
Below is a sample of the word document structure

1) Document content:


2) Footer:

The code sample is as follows:

            using (WordprocessingDocument doc = WordprocessingDocument.Open(@"C:\Users\dev5setup\Desktop\DEPT_TEST.docx", true))
            {
                Dictionary<string, string> tagMappings = GetTagMappingsForTemplate();

                IEnumerable<Paragraph> paras = doc.MainDocumentPart.Document.Descendants<Paragraph>();
                foreach (Paragraph para in paras)
                {
                    // get all runs under the paragraph and convert to be array
                    Run[] runArr = para.Descendants<Run>().ToArray();
                    // foreach each run
                    foreach (Run run in runArr)
                    {
                        string modifiedString = "";
                        int count = 0;
                        string innerText = run.InnerText;

                        #region replace tags
                        foreach (KeyValuePair<string, string> mapping in tagMappings)
                        {
                            if (count == 0)
                            {
                                modifiedString = run.InnerText.Replace(mapping.Key, mapping.Value);
                            }
                            else
                            {
                                modifiedString = modifiedString.Replace(mapping.Key, mapping.Value);
                            }                          
                            count++;
                        }
                        #endregion

                        // if the InnerText doesn't modify
                        if (modifiedString != run.InnerText)
                        {
                            Text t = new Text(modifiedString);
                            run.RemoveAllChildren<Text>();
                            run.AppendChild<Text>(t);
                        }
                    }
                }
                doc.MainDocumentPart.Document.Save();
             
                //Update the word document footer section
                FooterPart pp = doc.MainDocumentPart.FooterParts.ElementAt(0);
                IEnumerable<Paragraph> footerParas = pp.Footer.Descendants<Paragraph>();

                foreach (Paragraph footerPara in footerParas)
                {
                    // get all runs under the paragraph and convert to an array
                    Run[] runArr = footerPara.Descendants<Run>().ToArray();
                    // foreach each run
                    foreach (Run run in runArr)
                    {
                        string modifiedString = "";
                        int count = 0;
                        string innerText = run.InnerText;

                        #region replace tags
                        foreach (KeyValuePair<string, string> mapping in tagMappings)
                        {
                            if (count == 0)
                            {
                                modifiedString = run.InnerText.Replace(mapping.Key, mapping.Value);
                            }
                            else
                            {
                                modifiedString = modifiedString.Replace(mapping.Key, mapping.Value);
                            }
                            count++;
                        }
                        #endregion

                        // if the InnerText doesn't modify
                        if (modifiedString != run.InnerText)
                        {
                            Text t = new Text(modifiedString);
                            run.RemoveAllChildren<Text>();
                            run.AppendChild<Text>(t);
                        }
                    }
                }              
            }


Saturday, September 3, 2016

Read a Excel Cell value using OpenXML

//DLL references in the solution
DocumentFormat.OpenXml
Microsoft.Office.Interop.Excel

//using directives
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

//Method      
public string ReadCellValue(string fileName, string sheetName, string addressName)
        {
            string value = null;
         
            using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
            {
                WorkbookPart myWorkBookPart = document.WorkbookPart;
                Sheet theSheet = myWorkBookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();

                if (theSheet == null)
                {
                    throw new ArgumentException("sheetName");
                }

                WorksheetPart myWorkSheetPart = (WorksheetPart)myWorkBookPart.GetPartById((theSheet.Id));
                Cell targetCell = myWorkSheetPart.Worksheet.Descendants<Cell>().Where(c => c.CellReference == addressName).FirstOrDefault();

                if (targetCell != null)
                {
                    value = targetCell.InnerText;

                    if (targetCell.DataType != null)
                    {
                        switch (targetCell.DataType.Value)
                        {
                            case CellValues.SharedString:

                                var stringTable = myWorkBookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
                                if (stringTable != null)
                                {
                                    value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
                                }
                                break;

                            case CellValues.Boolean:
                                switch (value)
                                {
                                    case "0":
                                        value = "FALSE";
                                        break;
                                    default:
                                        value = "TRUE";
                                        break;
                                }
                                break;
                        }
                    }
                }
            }
            return value;
        }

//Call method parameters sample
ReadCellValue(@"C:\sample\My test workbook.xlsm", "Sheet Name", "E102");

Thursday, August 25, 2016

Update Managed Property & Manually Re-Index a SharePoint Library

The SharePoint crawler picks up content that has changed since the last crawl and updates the search index.

When you change a managed property or when you change the mapping of crawled and managed properties then the site must be re-crawled before he changes are reflected in the search index. Since changes are made in the search schema and not to the actual site, the crawler will not automatically re-index. To make sure that the changes are crawled and fully re-indexed, you must request a re-indexing. The site content will be re-crawled and re-indexed so that you can start using the managed properties in queries, query rules and display templates.

In my case I updated several managed property. After the update a re-indexing of the SharePoint library was required for the items to show up in the search.

Mapping the Managed property with the Crawled property


  • In the Central Administration go to the Search Service Application.
  • Go to Search Schema
  • Search for you Managed Property


  • Click on property in the search results.
  • Make the property Queryable so that this appear in search items
  • Click on the "Add a mapping" button and map with the crawled property

[Note: you can do the mapping other way around too.. By searching the crawled property and map the managed property to the crawled property, depending on your scenario]
  • Save changes

Re-Indexing the SharePoint library
  • Go to the  library settings page of the target SP library.
  • Select Advanced settings
  • Scroll down and click on the "Reindex Document Library" button
  • Click on "Reindex document library" button as shown below


  • The re-indexing will happen in the next scheduled crawl.

Monday, May 9, 2016

Hide Elements Associated to Master pages in Dialogs

Once I had a minor UI issue with a Modal dialog. Yet I thought to blog about it as it may be useful. An image attached to the master page and a button in the page overlapped in a Modal popup. The issue was due to the fact that the image's z-index was higher than the button according to the build up of the DOM tree. Once of the options is to send the image back using the z-index. As a quick fix can adjust the styling of the div containing the image as:

.myImageDiv {
    z-index: -1;
}

Anyway decided to remove the image only for popups. How can this be done? Well, in SharePoint 2013 you can use the UI class "ms-dialogHidden" in your div's. So when the page is displayed in a Modal popup, the divs containing this CSS class are not displayed.

<div class="myImageDiv ms-dialogHidden"></div>

That's it ! 

Saturday, April 16, 2016

Best practices when querying SharePoint lists/libraries

1) Golden rule - Never iterate through the whole list to filter/check-on couple of items in the list. List operations are heavy. Filter the required items needed maybe through a CAML query.

2) Use the SPQuery class if your objective is to get items from a single list

3) In your CAML query set ViewFields to filter the fields which you need. In the same way you can use SPList.GetItemByIdSelectedFields() method to get selected fields. Setting ViewFields makes the query more efficient

4) Use the SPSiteDataQuery class to get results from multiple lists. Here you can specify the web and lists which you are targeting at.

Example:

SPSiteDataQuery myQuery = new SPSiteDataQuery();
myQuery.query = "Your CAML query goes here";
myQuery.Webs = @"<Webs Scope=""SiteCollection"" />"; //Returns data from all webs in the current site collection
//myQuery.Webs = @"<Webs Scope=""Recursive"" />"; // will return from current web and its child webs

myQuery.Lists = @"<Lists ServerTemplate=""101"" />"; //101 refers to document libraries
myQuery.ViewFields =  @"
                                            <FieldRef Name=""Field One"" />
                                            <FieldRef Name=""Field Two"" />
                                           ";

Thursday, April 7, 2016

Saving lookup meta data values to library using Powershell - SharePoint

When you take an item in a list, the Lookup fields store its value in the following format
id;#string

when programmatically adding meta data to a list's column the lookup value has to be built before assigning to the item field.

In the below example I refer one lookup, get its value/string. Using the string, do a search for the lookup list item id in the lookup list. Then create the new lookup field. Finally update item


  $myLookupItem = [Microsoft.SharePoint.SPFieldLookupValue]($_["FieldOne_InternalName"])
  $newLookupId = GetLookupId $myLookupItem.LookupValue

  $newLookupItem = New-Object Microsoft.SharePoint.SPFieldLookupValue($newLookupId  ,$myLookupItem.LookupValue)

$_["FieldTwo_InternalName"] = $newLookupItem

$_.Update()
$_.File.CheckIn(" FieldTwo value updated", 1)

$_ is explained in an earlier post

Wednesday, April 6, 2016

Query SharePoint Libraries using CAML query and Powershell

$web = Get-SPWeb $siteUrl
$list = $web.Lists[$listName]

1) Query items in list

if($list -ne $null)
{

$caml = '<OrderBy><FieldRef Name="ID" Ascending="True" /></OrderBy><Where><And> <Geq> <FieldRef Name="ID" /><Value Type="Number">{0}</Value> </Geq><Leq><FieldRef Name="ID" /><Value Type="Number">{1}</Value></Leq> </And> </Where> ' -f $startValue,$endValue

$myQuery = new-object Microsoft.SharePoint.SPQuery
$myQuery.Query = $caml

$filteredItems = $list.GetItems($myQuery)

$filteredItems | ForEach-Object {

      #Assign meta data to variables
      $variableOne = $_["MetaDataOne_InternalName"]
}

}

2) Remove specific items from list

if($list -ne $null)
{

$caml='<Where> <Or> <Or> <Or> <Eq> <FieldRef Name="Title" /><Value Type="Text">{0}</Value> </Eq> <Eq> <FieldRef Name="Title" /><Value Type="Text">{1}</Value> </Eq> </Or> <Eq> <FieldRef Name="Title" /><Value Type="Text">{2}</Value> </Eq> </Or> <Eq> <FieldRef Name="Title" /><Value Type="Text">{3}</Value> </Eq> </Or> </Where> ' -f $itemOne, $itemTwo, $itemThree, $itemFour

$query=new-object Microsoft.SharePoint.SPQuery
$query.Query=$caml
$col=$list.GetItems($query)

Write-Host 'Number of items removed: ' $col.Count

$col | % {$list.GetItemById($_.Id).Delete()}

}

$web.Dispose()

for more info about CAML query syntax visit here

Tuesday, April 5, 2016

Access User Profile Service using Powershell


function GetInfo([string]$userAccount)
{

 $mailAttribute = "WorkEmail"

 $mail = ""

 $serviceContext = Get-SPServiceContext -Site $siteUrl
 $profileManager =  New-Object  Microsoft.Office.Server.UserProfiles.UserProfileManager($serviceContext);

if($profileManager.UserExists($userAccount))
{
        $userProfile = $profileManager.GetUserProfile($userAccount)
        $mail = $userProfile[$mailAttribute].Value
}

return $mail
}

Get SharePoint user group and user details using Powershell

$SPWebCollection = $SPSite.AllWebs

$rootSite = $SPSite.RootWeb

foreach($SPGroup in $rootSite.Groups)
{
foreach($user in $SPGroup.users)
{
$users = new-object psobject
$users | add-member noteproperty -name "Group Name" -value $SPGroup.Name
$users | add-member noteproperty -name "User" -value $user
$users | add-member noteproperty -name "Display Name" -value $user.DisplayName

$email = GetInfo  $user
$users | add-member noteproperty -name "Work Email" -value $email
$combinedusers =[Array]$combinedusers + $users
}
}

        #Create CSV file
$filelocation=$filePath+"\"+$rootSite+".csv"
$combinedUsers | export-csv -path $filelocation -notype
$combinedUsers = $null

Friday, January 15, 2016

Ajax.BeginForm Example - ASP.NET MVC

In this example I use an ajax form to load search results.

1) In my view I add the Ajax form.

The form invokes the "SearchResult" action

@using (Ajax.BeginForm("SearchResult", "Search", new AjaxOptions
{
    HttpMethod = "GET",
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "searchResults"
}))
{
    <input type="text" name="q" />
    <input type="submit" value="Search" />  
}

<table id="searchResults">

</table>

2) The Action

public PartialViewResult SearchResult(string q)
        {
            var books = BookDB.GetBooks().Where(r => r.Name.Contains(q) || String.IsNullOrEmpty(q)).Take(10);
            return PartialView("_SearchResults", books);
        }

3)  The partial view to display search results

@using MvcBookReview.Infrastructure
@model IEnumerable<MvcBookReview.Models.BookReview>

<table id="searchResults">
    @foreach(var item in Model)
    {
    <tr>
        <td>
            <table>
                <tr>
                    <td><b>Book:</b> @item.Name</td>
                </tr>
                <tr>
                    <td><b>Rating:</b> @item.Rating</td>
                </tr>
            </table>
        </td>
        <td>
            <div class="bookitem">
                @Html.Image(item.ImageUrl, item.AlternateText)
            </div>
        </td>
    </tr>
    }
</table>

Note: Here I use the custom helper created in an earlier post


The Result: 
From left to right
    1) Search all
    2) Search text = "TinTin"
    3) Search text = "Asterix"


Thursday, January 14, 2016

Anti Cross Site Scripting Library - .NET

In case you have enable users to input html without validating and display without encoding (Eg: Using @Html.Raw), then you make the site prone to XSS. .NET provides an Anti XSS library to use in such scenarios.

1) Download the library through VS NuGet package manager


2) The following DLL's will be added in the solution reference










3) Use the library to remove all XSS causing scripts that may be included in  the user inputs.

Example:
review.Body = Sanitizer.GetSafeHtmlFragment(review.Body);

Wednesday, January 13, 2016

Ajax ActionLink - ASP.NET MVC

In this example I create an Ajax Action Link. Using the ActionLink load a partial view to the page.

1. In my view I create an ActionLink as

<div  id="latestReview">
    @Ajax.ActionLink("Get Latest Review", "LatestReview", new AjaxOptions
{
    UpdateTargetId = "latestReview",
    InsertionMode = InsertionMode.Replace,
    HttpMethod = "GET",
    LoadingElementId = "progress"
})
</div >

also add another div for later use

<div id="progress">
    <img src="@Url.Content("~/Images/loading.gif")" />
</div >


In @Ajax.ActionLink()

  • The second parameter is the Action method which will be invoked on click
  • The third parameter specifies the ajax options


In the AjaxOption

  • The "UpdateTargetId" specifies the location in the DOM to display the result.
  • The "InsertionMode" provides the options such as Before, after or replace.
  • The "LoadingElementId" specifies the "progress" div to display until the view is partial view loaded

2. Next, in the controller create an Action method

In this example I omit the DB calls, instead create a dummy object of type BookReview. Note the return is a partial view


        public PartialViewResult LatestReview()
        {
            var modelTwo = new BookReview()
            {
                Name = "Samson",
                Rating = 7
            };
            Thread.Sleep(2000);
            return PartialView("_Review", modelTwo);
        }

a delay is created to show the "LoadingElementId" behaviour in the link

3. Create the partial view

@model MvcBookReview.Models.BookReview

<div class="review">
    <table class="rating">
        <tr class="ratinghead"><th>User</th><th>Rating</th></tr>
        <tr><td>@Model.Name</td><td>@Model.Rating</td></tr>
    </table>       
</div>

Note:
If you don't have the JQuery unobtrusive ajax library ("jquery.unobtrusive-ajax.min.js")in your solution, the ajax action link would not work properly. Add it to your solution through the Visual Studio Nuget Package Manager.

Result
The 3 stages: link, while processing action, result


When you have a look at the link through the browser's developer tool you will see something like this


Tuesday, January 12, 2016

Razor Helper - ASP.NET MVC

There are two ways to implement this

Razor helper can be added directly to a view. 
For an instance lets go into the _Layouts.cshtml view and add the below Razor helper after the </html> tag

@helper Script(string scriptName) { 
    <script src="@Url.Content("~/Scripts/" + scriptName)" type="text/javascript"></script>
    }

Now at the top of the page within the <head> tag you could reference the razor helper as:

@Script("jquery-1.4.4.js")
@Script("jquery-1.4.4.min.js")

- OR -

Rather than having the Razor helpers at the bottom of the view page, you could move it to a separate file inside app_code. For that we need to do the below changes

1. Add the app_code folder in the solution if not available
2. Inside the folder create a MVC View Page(Razor). The page I created in my example is Content.cshtml
3. Delete all mark-up available in the page and move the helper script into the page

So the below code goes to the newly created view. You need to have the using directive 

@using System.Web.Mvc;

@helper Script(string scriptName, UrlHelper url)
{
    <script src="@url.Content("~/Scripts/" + scriptName)" type="text/javascript"></script>
}

4. In the view file (Eg: _Layout.cshtml)  refer the helper  as:

   @Content.Script("jquery-1.4.4.js", Url)
   @Content.Script("jquery-1.4.4.min.js", Url)





Monday, January 11, 2016

Display Annotations - ASP.NET MVC

ASP.NET MVC display annotations are pretty strait forward. Let's go for an example strait away.
I have an Employee class

        [Required]
        public virtual string Name { get; set; }

        public virtual string Address { get; set; }

        [DisplayName("Date of birth")]
        [DataType(DataType.Date)]
        public virtual DateTime DateOfBirth { get; set; }

        [Range(1, 5)]
        public virtual int Tier { get; set; }

        [DataType(DataType.Password)]
        public virtual string Password { get; set; }

        [DataType(DataType.MultilineText)]
        public virtual string Comments { get; set; }

        [DisplayName("Start date")]
        [DataType(DataType.Date)]
        public virtual DateTime StartDate { get; set; }

Output:


Friday, January 8, 2016

Create Custom Validator - ASP.NET MVC

In this example I am using a sample class called Employee class. I do a custom validation for the field "Date of birth". The Employee class looks something like below. Notice that the class inherits the IValidatableObject interface in order to implement the custom validation. Afterwards the Validate() method is implemented.

    public class Employee : IValidatableObject
    {
        public virtual int ID { get; set; }

        [Required]
        public virtual string Name { get; set; }
        public virtual string Address { get; set; }
        public virtual DateTime DateOfBirth { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var field = new[] { "DateOfBirth" };
            if (DateOfBirth > DateTime.Now)
            {
                yield return new ValidationResult("Invalid date of birth", field);
            }
        }
    }

If you don't use a second parameter when instantiating the ValidationResult object, then the validation message would show up on the top of the form in the Validation summary section

Result


Thursday, January 7, 2016

Create Custom Helpers - ASP.NET MVC

1) Create extension method

Here inside my helper class I did the following coding

using System.Web.Mvc;
...
...
public static class MyHelpers
    {
        public static MvcHtmlString Image(this HtmlHelper helper, string src, string alterText)
        {
            var builder = new TagBuilder("img");
            builder.MergeAttribute("src", src);
            builder.MergeAttribute("alt", alterText);
            return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
        }
    }

2) Add the using directive in the View

The helper class resides within the "MvcBookReview.Infrastructure" namespace. Hence:

@using MvcBookReview.Infrastructure


3) Call the custom helper in view

<div>
    @Html.Image(@Model.ImageUrl, @Model.AlternateText)
</div>

Result:





Wednesday, January 6, 2016

HTML5 - Drawing 2D on Canvas

Rectangle
fillRect(x coordinate, y coordinate, width, height)

Round
arc(x coordinate, y coordinate, start angle, end angle, clockwise-or-counter-clockwise)

Linear Gradient
createLinearGradient(Start point - x coordinate, Start point - y coordinate, End point - x coordinate, End point - y coordinate)

Draw Text
fillText("The actualk text goes here", Start point - x coordinate, Start point - y coordinate)

Quadratic Bézier Curve
moveTo(Start point - x coordinate, Start point - y coordinate); //specify the start point
ctx.quadraticCurveTo(Bézier control point - x coordinate, Bézier control point - y coordinate,  End point - x coordinate, End point - y coordinate);

Example

<html>
<body>

<canvas id="myCanvas" width="400" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>
//1 Capture the canvas
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

//2 Create gradient
var grd = ctx.createLinearGradient(0,0,200,0);
grd.addColorStop(0,"blue");
grd.addColorStop(1,"black");

//3 Fill gradient
ctx.fillStyle = grd;
ctx.fillRect(10,200,150,80);


//4 Draw text inside the callout
var ctx = c.getContext("2d");
ctx.font = "17px Arial";
ctx.fillText("Hello World",32,70);

//5 Arc
ctx.arc(200, 400, 50, 0, 2 * Math.PI, false);
ctx.fillStyle = '#00994c';
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = '#003300';
ctx.stroke();

//6 Quadratic Bézier Curve
ctx.moveTo(75,25);
ctx.quadraticCurveTo(25,25,25,62.5);
ctx.quadraticCurveTo(25,100,50,100);
ctx.quadraticCurveTo(50,120,30,125);
ctx.quadraticCurveTo(60,120,65,100);
ctx.quadraticCurveTo(125,100,125,62.5);
ctx.quadraticCurveTo(125,25,75,25);
ctx.stroke();

</script>
</body>
</html>

Result