Customize icon for Ribbon UI custom action in Sharepoint 2013 hosted app

So you are building a Sharepoint hosted app and you started to use a UI custom action. Lets take a ribbbon action button as an example; you want this button to appear associated with the selected list in every list of you host web. This is very powerful as this acts as a bridge between the host web and your app.

This code is an example of this UI custom action:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="c2747e1a-8d9a-451f-bb02-59f0e7cbae69.RibbonCustomAction2"
     RegistrationType="ContentType"
     RegistrationId="0x01"
     Location="CommandUI.Ribbon"
     Sequence="10001"
     Title="Create a Live Chart">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.List.Actions.Controls._children">
          <Button Id="Ribbon.List.Actions.RibbonCustomActionButton"
             Alt="Create Chart"
             Sequence="100"
             Command="Invoke_RibbonCustomActionButtonRequest"
             LabelText="Create Chart"
             TemplateAlias="o1"
             Image32by32="_layouts/15/images/placeholder32x32.png"
             Image16by16="_layouts/15/images/placeholder16x16.png"/>
          </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="Invoke_RibbonCustomActionButtonRequest"
                          CommandAction="~remoteAppUrl/Pages/Default.aspx?{StandardTokens}&amp;SPListItemId={ItemId}&amp;SPListId={ListId}"/>
      </CommandUIHandlers>
    </CommandUIExtension >
  </CustomAction>
</Elements>

Have a look at the highlighted code in the previous block you will noticed that the icon of the button is a placeholder you have the ability to change. The next screenshot show the button with the placeholder icon:
ribbon custom icon placeholder

You may think that changing this icon is easy, unfortunately its not! My first try and what I think it should be working is adding my custom icon to a module in the app project and reference it using the ~appWebUrl token so icon attributes url should be something like this: Image32by32=”~appWebUrl/images/myIcon.png”. As you can guess now, this didn’t work because SharePoint 2013 don’t replace this token with the app web path which will lead to a broken image.

Solution
I came up with two worarounds for this : the first one is to deploy the icon in a way that its publicly accessible through a fixed url and use a url like this:

 <CommandUIDefinition Location="Ribbon.List.Actions.Controls._children">
          <Button Id="Ribbon.List.Actions.RibbonCustomActionButton"
             Alt="Create Chart"
             Sequence="100"
             Command="Invoke_RibbonCustomActionButtonRequest"
             LabelText="Create Chart"
             TemplateAlias="o1"
             Image32by32="http://www.mysite.com/images/customIcon.png"
             Image16by16="http://www.mysite.com//images/customIcon.png"/>
          </CommandUIDefinition>
</CommandUIDefinitions>

I don’t like this approach as its involves managing resources outside of the app which is a bit of a headache of course.

A better workaround is to use Data URIs which is a way of embedding the actual image data in the src attribute of the img tag. The only limitation is browser support for example this is not supported in IE5 to IE7 but its supported starting from IE8.

The code after applying this workaround will be like this:

<CommandUIDefinition Location="Ribbon.List.Actions.Controls._children">
          <Button Id="Ribbon.List.Actions.RibbonCustomActionButton"
             Alt="Create Chart"
             Sequence="100"
             Command="Invoke_RibbonCustomActionButtonRequest"
             LabelText="Create Chart"
             TemplateAlias="o1"
             Image32by32="data:image/png;base64,iVBORw0KGgoAAAANSU..."
             Image16by16="data:image/png;base64,iVBORw0KGgoAAAANSU..."/>
</CommandUIDefinition>

And this will work!
Screen Shot 2013-07-03 at 11.43.22 PM

One last thing: There are a lot of image data URI generators online like this one.

Good luck!

Posted in Software | Tagged | 2 Comments

Using tSQLt FakeTable with table referenced by indexed views

tSQLt_Database_Unit_Testing_for_SQL_Server__Logo_210x160If you tried to use tSQLt FakeTable to fake a table that is referenced by an object -in most cases: indexed view- is declared using a WITH SCHEMABINDING clause, your test case will fail with this SQL exception:

System.Data.SqlClient.SqlException: Object ‘table name’ cannot be
renamed because the object participates in enforced dependencies

What WITH SCHEMABINDING means is to notify SQL server that this view is tied to the schema of this one or more tables. Thats why you can not make indexed view unless you declare the view with WITH SCHEMABINDING clause.

A quick solution for this problem could be done simply by dropping these referenced objects inside the unit test code:

CREATE PROCEDURE testFinancialApp.[test that ConvertCurrencyUsingLookup converts using conversion rate in CurrencyConversion table]
AS
BEGIN
    DECLARE @expected MONEY; SET @expected = 3.2;
    DECLARE @actual MONEY;
    DECLARE @amount MONEY; SET @amount = 2.00;
    DECLARE @sourceCurrency CHAR(3); SET @sourceCurrency = 'EUR';
    DECLARE @destCurrency CHAR(3); SET @destCurrency = 'USD';

------Drop the view that is using this table
    DROP VIEW FinancialApp.CurrencyConversionView;

------Fake Table
    EXEC tSQLt.FakeTable 'FinancialApp.CurrencyConversion';

    INSERT INTO FinancialApp.CurrencyConversion (id, SourceCurrency, DestCurrency, ConversionRate)
                                         VALUES (1, @sourceCurrency, @destCurrency, 1.6);
------Execution
    SELECT @actual = amount FROM FinancialApp.ConvertCurrencyUsingLookup(@sourceCurrency, @destCurrency, @amount);

------Assertion
    EXEC tSQLt.assertEquals @expected, @actual;
END;
GO

Of course you should know already that tSQLt executes unit test stored procs inside of a transaction that is always rollbacked, so no need to re create the view again.

But what if you are using this view in your unit test logic? not mentioning that you will have to manually add this drop logic to all of your unit tests which is not handy if you are working on a large application. based on this post which most of the code in this post is based on: How to FakeTable when table is referenced by objects with schemabinding clause?; we can alter the definition of these objects and remove the WITH SCHEMABINDING clause, this will not affect our unit tests at all because the views are still there for us to use. However and because you cannot have indexes on objects that are not declared using WITH SCHEMABINDING; we will have to remove all clustered indexes on indexed views, what I noticed is that when dropping clustered indexes in that case, non-clustered indexes are dropped as well.

A complete sample for this process here:


CREATE PROCEDURE [tSQLt].[PrepareTableForFaking]
        @TableName NVARCHAR(MAX),
        @SchemaName NVARCHAR(MAX)
AS
BEGIN

  --remove brackets
  select @TableName = (REPLACE(REPLACE(@TableName, '[', ''), ']', ''));
  select @SchemaName = (REPLACE(REPLACE(@SchemaName, '[', ''), ']', ''));

-- delete temptable
  IF EXISTS(SELECT * FROM tempdb..sysobjects WHERE id = OBJECT_ID('tempdb.dbo.#temp'))
    DROP TABLE #TEMP

  --recursively get all referencing dependencies
;WITH ReferencedDependencies (parentId, name, LEVEL)
  AS(
      SELECT DISTINCT o.object_id AS parentId, o.name, 0 AS LEVEL
        FROM sys.sql_expression_dependencies AS d
        JOIN sys.objects AS o
          ON d.referencing_id = o.object_id
            AND o.type IN ('FN','IF','TF', 'V', 'P')
            AND is_schema_bound_reference = 1
        WHERE
          d.referencing_class = 1 AND referenced_entity_name = @TableName AND referenced_schema_name = @SchemaName
      UNION ALL
      SELECT o.object_id AS parentId, o.name, LEVEL +1
        FROM sys.sql_expression_dependencies AS d
        JOIN sys.objects AS o
                ON d.referencing_id = o.object_id
            AND o.type IN ('FN','IF','TF', 'V', 'P')
            AND is_schema_bound_reference = 1
        JOIN ReferencedDependencies AS RD
                ON d.referenced_id = rd.parentId
  )

  -- select all objects referencing this table in reverse level order
  SELECT DISTINCT IDENTITY(INT, 1,1) AS id, name, OBJECT_DEFINITION(parentId) as obj_def, parentId as obj_Id , LEVEL
  INTO #TEMP
  FROM ReferencedDependencies
  WHERE OBJECT_DEFINITION(parentId) LIKE '%SCHEMABINDING%'
  ORDER BY LEVEL DESC
  OPTION (Maxrecursion 1000);

  --prepere the query to remove all dependent indexes (this is nessesary to removing (with schemabinding) later)
  DECLARE @qryRemoveIndexes NVARCHAR(MAX);
  SELECT @qryRemoveIndexes = (
  SELECT 'DROP INDEX ' + i.name + ' ON ' + OBJECT_NAME(o.id) + '; ' FROM sys.sysobjects AS o
  INNER JOIN #TEMP ON o.id = #TEMP.obj_Id
  INNER JOIN sys.sysindexes AS i ON i.id = o.id
  where i.indid = 1 -- 1 = Clustered index (we are only interested in clusterd indexes)
  FOR XML PATH(''));
  --excute @qryRemoveIndexes
  exec sp_executesql @qryRemoveIndexes;

  --change the definition for removing (with schemabinding) from those objects
  DECLARE @currentRecord INT
  DECLARE @qryRemoveWithSchemabinding NVARCHAR(MAX)
  SET @currentRecord = 1
  WHILE (@currentRecord <= (SELECT COUNT(1) FROM #TEMP) )
  BEGIN
          SET @qryRemoveWithSchemabinding = ''
          SELECT @qryRemoveWithSchemabinding = #TEMP.obj_def
            FROM #TEMP
            WHERE #TEMP.id = @currentRecord
          SET @qryRemoveWithSchemabinding = REPLACE(@qryRemoveWithSchemabinding,'CREATE', 'ALTER')
          SET @qryRemoveWithSchemabinding = REPLACE(@qryRemoveWithSchemabinding,'with schemabinding', ''); -- remove schema binding
          --excute @qryRemoveWithSchemabinding
          EXEC sp_executeSQL @qryRemoveWithSchemabinding;
          SET @currentRecord = @currentRecord + 1
  END

END

What we can do now is just to add this line of code inside [tSQLt].[FakeTable] stored proc:

   --after executing Private_ValidateFakeTableParameters
   EXEC tSQLt.PrepareTableForFaking @TableName, @SchemaName;

enjoy!

Posted in Software | Tagged , , | Leave a comment

Using AngularJS to consume WebAPI service in MVC4 project

AngularJS is a very powerful javascript framework with very big set of features like letting you extend HTML syntax to express your application components, two way data binding between your DOM and your  model, dependancy injection and inversion of control in the browser! and it makes testing your javascript code very easy.

In this article I will show you how easy it is to setup your application to use AngularJS and as a start we will use it to consume the WebApi service on the server.

The Solution:
So we have an MVC4 project with a WebAPI controller that handles GET, PUT operations on a group of blog posts. the code for this controller looks like this:

using System.Collections.Generic;
using System.Linq;
using Blog13.Data;

namespace Blog13.Web.Services.Controllers
{
    public class PostsViewModel
    {
        public string Title { get; set; }
        public string Body { get; set; }
        public int Id { get; set; }
        public string AuthorName { get; set; }
        public string[] Tags { get; set; }
    }

    public class PostsController : BlogBaseApiController
    {
        private readonly EfRepository _repository;

        public PostsController()
        {
            _repository = new EfRepository(new EfDbContext());
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _repository.Dispose();
            }
            base.Dispose(disposing);
        }

        // GET api/Posts
        public IEnumerable<PostsViewModel> Get()
        {
            System.Threading.Thread.Sleep(5000); //only for testing loading time..remove in production code
            return _repository.GetPosts().Select(obj => new PostsViewModel()
            {
                AuthorName =  obj.Author.Name,
                Title =  obj.Title,
                Id =  obj.Id,
                Body =  obj.Body,
                Tags =  obj.Tags.Select(tag => tag.Value).ToArray()
            });
        }

        // PUT api/Posts
        public void Put(IEnumerable<PostsViewModel> posts)
        {
            System.Threading.Thread.Sleep(5000); //only for testing loading time..remove in production code
            //TODO: update posts
        }

    }
}

At this point if we used Fiddler to execute a GET request to /api/posts/ we will have a JSON result as in this image:
Screen Shot 2013-02-03 at 3.16.34 PM

Adding AngularJS
In master page or like in my case _layout.cshtml (as I’m using Razor) you will have to make two changes:

  1. In html tag add ng-app attribute which indicate to the AngularJS framework that this is an AngularJS application
    <!DOCTYPE html>
    <html ng-app>
    <head>
    
  2. Inside head element add a script entry for the AngularJS file
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
    

Using AngularJS
I decided to load these posts in my home index view so this is the code that exists in my Views/Home/Index.cshtml file:

<script src="~/Scripts/PostsController.js"></script>
<div ng-controller="PostsController">
    <strong class="error">{{ error }}</strong>
    <strong ng-show="loading">loading..</strong>
    <div ng-repeat="post in posts">
        <strong ng-hide="editMode">{{ post.Title }}</strong>
        <input ng-show="editMode" type="text" ng-model="post.Title"/>
        <p ng-hide="editMode">{{ post.Body }}</p>
        <p ng-show="editMode"><textarea ng-model="post.Body"></textarea></p>
        <span ng-repeat="tag in post.Tags">
            <span>{{ tag }} </span>
        </span>
        <p>Author: {{ post.AuthorName }}</p>
        <hr/>
    </div>
    <div ng-show="posts.length > 0">
        <a ng-click="toggleEdit()" href="javascript:;">Edit</a>
        <a ng-click="save()" href="javascript:;">Save</a>
    </div>
</div>

As you can see, the most notable thing is using MVC pattern here so top most div in this component declares this attribute: ng-controller="PostsController" this means that the framework will use the controller PostsController to handle this portion of the page (the view).

PostsController itself is declared in the javascript file that is added on the first line in a script element with the src="~/Scripts/PostsController.js" So lets have a look at this file:

function PostsController($scope, $http) {

    $scope.loading = true;
    $scope.editMode = false;

    $http.get('/api/posts/').success(function (data) {
        $scope.posts = data;
        $scope.loading = false;
    })
    .error(function () {
        $scope.error = "An Error has occured while loading posts!";
        $scope.loading = false;
    });

    $scope.toggleEdit = function() {
        $scope.editMode = !$scope.editMode;
    };

    $scope.save = function() {
        $http.put('/api/posts/', $scope.posts).success(function (data) {
            alert("Saved Successfully!!");
        }).error(function (data) {
            $scope.error = "An Error has occured while Saving posts! " + data;
            $scope.loading = false;
        });
    };

}

controller code is very easy and self explaining, its just a function, the name of the function is the name of the controller that is used in the markup, the function takes two parameters the first one is the most important $scope this is the object that is getting bound to the DOM for example if in this function I set $scope.foo = "bar"; in markup I can use this binding expression <span>{{ foo }}</span> so I will have the string “bar” in my span after binding.

The other parameter $http gets resolved for you using the AngularJS DI framework to The $http service in core Angular that facilitates communication with the remote HTTP servers via browser’s XMLHttpRequest object or via JSONP. Its usage is very self explanatory in the previous code.

Running the application
So lets see what these two bits of codes did..when we start this application we will see a loading indicator
Screen Shot 2013-02-03 at 4.10.01 PM
after a while is disappears when data is loaded, then the loaded data is bound and appears to the viewer
Screen Shot 2013-02-03 at 4.10.08 PM
When a user clicks on Edit link the view shows editable text boxes instead of labels
Screen Shot 2013-02-03 at 4.10.20 PM
clicking save will post the modified data back to the server using a PUT http verb. I have added a breakpoint in the Put controller action and this is the list of modified posts just as expected
Screen Shot 2013-02-03 at 4.17.24 PM
pretty neat! so enjoy it!!

Posted in Software | Tagged , , , | Leave a comment

Readify Developer Network – An “Agile” Agile Primer

I thought it will be nice to share this while am watching it…very interesting especially the way this talk was organized. This is a Live recording of a presentation done 26-Feb-08 in Sydney as part of the Readify Developer Network. This is a presentation on agile methodologies (e.g Scrum, XP, etc) where the content was determined by the audience and covers questions such as upfront estimating, being agile in a non-agile company, scope management and more.

Readify
Presenter: Richard Banks

Video | Posted on by | Tagged , | Leave a comment

Using PowerShell scripts for common SharePoint Server 2010 tasks

One of the great things introduced by SharePoint Server 2010 is PowerShell support. Previously -and by this I mean in SharePoint Server 2007- developers and SharePoint administrators was using Stsadm which a command-line tool for SharePoint 2007. The benefits of using PowerShell over Stsadm is countless includes but not limited to using the powerful capabilities of PowerShell like accessing file system, registry..etc ; that’s why Stsadm support only exists in SharePoint 2010 for backward compatibility but its deprecated.

This is a sample of a PowerShell script that can use to create a site collection based on prompting the user for a url, owner, and a title:

Clear-Host #Clear Screen
Add-PSSnapin Microsoft.Sharepoint.PowerShell -ErrorAction "SilentlyContinue" #adds reference to SharePoint (-ErrorAction "SilentlyContinue") only for running inside Powershell ISE
Write-Host "Starting Sharepoint SPSite Creator..." #outputing a starting string
$url = Read-Host "The URL of the SPSite to create?" #asking for user input
$owner = Read-Host "domain/user?" #asking for user input
$title = Read-Host "Site Title?" #asking for user input
Remove-SPSite -Identity $url -ErrorAction "SilentlyContinue" #remove the site if exists
$site = New-SPSite -Url $url -OwnerAlias $owner -Template STS#1 -Name $title #Create the Site Collection (STS#1) is the blank template
Write-Host $site.RootWeb.Title " has been successfully created with url: " $site.Url #outputing a success string

You can simply write this using notepad and save it with “.ps1″ extension and you are good to go, however its better to use PowerShell ISE (PowerShell integrated scripting environment) to get syntax highlighting, debugging..etc

Posted in Software | Tagged , | Leave a comment

Convert Word documents to PDF and XPS documents in .Net

In a previous old post actually two years ago I talked about converting HTML documents to Microsoft Word documents using the Microsoft Office application’s COM-based object model and it was very nice and easy task.

But what about PDF? actually there are tons of HTML to PDF converters out there for a long time, however, straggling with their feature lists, prices and support plans is not a fun thing at all; That’s  why two years ago I decided – in a project I was working on- to only export to Word and leave PDF generation to another point in future.

However things had changed now since Microsoft decided to add exporting to PDF and XPS document to its feature list starting from Office 2010. Of course we can use this in our applications by working with the Office application’s COM-based object model. This is a very handy method that converts a Word document to a PDF document.

public static void SaveAsPDF(string wordFilePath, string PdfFilePath)
{
    Application word = null;
    Document document = null;

    FileInfo SrcFile = new FileInfo(wordFilePath);
    FileInfo DestFile = new FileInfo(PdfFilePath);
    if (SrcFile.Exists == false)
    {
        throw new Exception(wordFilePath + " doesn't exist.");
    }

    try
    {
        word = new Application();
        document = new Document();

        document = word.Documents.Add();
        word.Visible = false;

        document = word.Documents.Open(SrcFile.FullName);

        document.Activate();

        document.ExportAsFixedFormat
            (
            DestFile.FullName,
            Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF
            );


        document.Close(false);
        word.Quit();
    }
    catch (Exception ex)
    {
        try
        {
            document.Close(false);
            word.Quit();
        }
        catch (Exception)
        {
            //nothing
        }
        throw ex;
    }
}

The only thing that we need to change if we want to export to XPS is this line:

Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF //PDF
Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatXPS //XPS

Finally one good thing I noticed; – but I didn’t try out before- you don’t have to own and install Microsoft Office on your server to make use of this, I noticed that Microsoft Office Primary Interop Assemblies are available for download for free, I will much appreciate if someone try these out and give me his feedback.

Posted in Software | Tagged , , | Leave a comment

How to render asp.net control to HTML string by code

Sometimes you will need to programatically get the HTML markup of a server or a user control that normally will be rendered to the HTTP response by the ASP.Net framework.

This can simply be done with something like this:

/// <summary>
/// Returns the generated HTML markup for a Control object
/// </summary>
private string RenderControl(Control control)
{
      StringBuilder sb = new StringBuilder();
      StringWriter sw = new StringWriter(sb);
      HtmlTextWriter writer = new HtmlTextWriter(sw);

      control.RenderControl(writer);
      return sb.ToString();
}

This is simple but unfortunately not enough to help us unless you already in the scope/life cycle of a  System.Web.UI.Page and the control that you are dealing with is already in the control tree of that page; which is not always the case.

One of the problems we will usually face -if not inside a page scope- is if the control we are dealing with requires to be inside of a runat=”server” form. If this is the case you will be facing an exception telling you that you have to add the control inside of a from. You can fix that by creating a new Page and a new HtmlForm object and hook thinks together like that:

//initialize a new page to host the control
Page page = new Page();

//create the runat="server" from that must host asp.net controls
HtmlForm form = new HtmlForm();
form.Name = "form1";
page.Controls.Add(form);
form.Controls.Add(control);
//call RenderControl method to get the generated HTML
string html = RenderControl(control);

Then you will be facing the last exception RegisterForEventValidation can only be called during Render(); . Actually I couldn’t fix this without disabling event validation on the newly created page which in my case makes a lot of sense. You disable event validation on the page like this:

page.EnableEventValidation = false;

A complete solution

This is a complete solution that makes use of a Generic Handler that renders a .ascx user control as an HTML document:

using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Text;
using System.IO;
using System.Web.UI.HtmlControls;

namespace UserControlHandlerDemo.Web
{
    /// <summary>
    /// Renders a (.ascx) user control
    /// </summary>
    public class UserControlHandler : IHttpHandler, IRequiresSessionState
    {
        private const string BASE_DIRECTORY = "~/controls/";

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/html";

            //get name from GET or POST parameter
            string controlName = context.Server.UrlDecode(context.Request.Params["name"]);
            if (!string.IsNullOrEmpty(controlName))
            {
                try
                {
                    //define full virtual path
                    var fullPath = BASE_DIRECTORY + controlName;
                    
                    //initialize a new page to host the control
                    Page page = new Page();
                    //disable event validation (this is a workaround to handle the "RegisterForEventValidation can only be called during Render()" exception)
                    page.EnableEventValidation = false;
                    
                    //create the runat="server" from that must host asp.net controls
                    HtmlForm form = new HtmlForm();
                    form.Name = "form1";
                    page.Controls.Add(form);

                    //load the control and add it to the page's form
                    Control control = page.LoadControl(fullPath);
                    form.Controls.Add(control);

                    //call RenderControl method to get the generated HTML
                    string html = RenderControl(page);
                    
                    //output it to the response stream
                    context.Response.Write(html);
                }
                catch (Exception ex)
                {
                    //output error messege to the response stream
                    context.Response.Write("Error: " + ex.Message);
                }

                //end the response
                context.Response.End();
            }

        }


        /// <summary>
        /// Returns the generated HTML markup for a Control object
        /// </summary>
        private string RenderControl(Control control)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            HtmlTextWriter writer = new HtmlTextWriter(sw);

            control.RenderControl(writer);
            return sb.ToString();
        }




        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    
    }
}

Posted in Software | Tagged , | 5 Comments