Back to basics – calling methods in C#

Most of my experience is based on JavaScript, which is heavily used in SharePoint 2013 development. However, C# is not quite an obsolete language for SharePoint, so I think is a good idea to review basic C# knowledge. The scope for today is to show how to call methods with parameters. Even it looks very basics, you can be sure some of the knowledge are pretty much new for the beginners.

Simple call of a method with parameters

The most simple case is to call a methods with non optional, out or ref parameters. The case is illustrated below and produce expected output, which is “Andrei Popescu”.

 class Program
    {
        
        static void Main(string[] args)
        {
            Program prg = new Program();
        }


        public Program()
        {
            Console.Write(this.SimpleMethodCalling("Andrei", "Popescu"));
            Console.ReadKey();

        }

        string SimpleMethodCalling(string firstName, string lastName)
        {
            return firstName + " " + lastName;
        }
    }

Studying this example, you can figure out the main rule when calling a method is to provide parameters respecting the order. However, this is not always the case, as you can see in the situation below.

Calling a method with named parameters

This a second possible situation you might see while you do programming in C#. If you do not want to pass parameters in the specified order, you can call the method by naming explicitly parameters. Is not something you will see often, but is good to know this is possible.

    class Program
    {
        
        static void Main(string[] args)
        {
            Program prg = new Program();
        }


        public Program()
        {
            Console.Write(this.MethodCalledWithNamedParameters(lastName: "Last name", firstName: "First name"));
            Console.ReadKey();

        }

        string MethodCalledWithNamedParameters(string firstName, string lastName)
        {
            return firstName + " " + lastName;
        }
    }

Providing out parameter to a method

If the previous case is not often used, this is. Providing out parameter to a method is representing a technique to obtain an output besides what method is returning.


    class Program
    {
        
       private string _fullName;


        static void Main(string[] args)
        {
            Program prg = new Program();
        }


        public Program()
        {
            this.MethodWithOut("First name", "Last name", out this._fullName);
            Console.Write(this._fullName);
            Console.ReadKey();

        }

        void MethodWithOut(string firstName, string lastName, out string fullName)
        {
            fullName = firstName + " " + lastName;
        }
    }

What you need to keep in mind is out parameter needs to be assigned inside the method, otherwise you will face an error, which in our case will be: “The out parameter ‘fullName’ must be assigned to before control leaves the current method”. So I think is safe to say providing an out parameter is also a good practice if you want to be sure developers working on your code will assign a value to it.

If we are discussing this case, let’s try to combine it with previous one and try to call the method with out and named parameters in the same time. Let’s try first placing the named parameters before out one.

this.MethodWithOut(firstName: "First name", lastName:"Last name", out this._fullName);

This code will fail with this error: “Named argument specifications must appear after all fixed arguments have been specified”. And this is leading us to another rule When you use named parameters combined with fixed ones, please put named arguments after all fixed parameters have been specified. The correct code will be:

// We changed the signature
void MethodWithOut( out string fullName, string firstName, string lastName)
{
   fullName = firstName + " " + lastName;
}
// We call method with named parameters
this.MethodWithOut(out this._fullName, firstName: "First name", lastName:"Last name");

Providing ref parameter to a method

In general, a ref parameter is similar with out parameter, with a small difference. When you provide a ref parameter, you are not forced to assign a value to it inside a method.

  class Program
    {
        
        
        private string _fullName = "Andrei Popescu";

        static void Main(string[] args)
        {
            Program prg = new Program();
        }


        public Program()
        {

            // We do not perform any action on ref parameter and no error occurs
            this.MethodWithRefNoAction(ref this._fullName, firstName: "First name", lastName: "Last name");
            Console.Write(this._fullName);
            // We change ref parameter
            this.MethodWithRef(ref this._fullName, firstName: "First name", lastName: "Last name");
            Console.Write(this._fullName);
            Console.ReadKey();

        }

        void MethodWithRefNoAction(ref string fullName, string firstName, string lastName)
        {

        }
        void MethodWithRef(ref string fullName, string firstName, string lastName)
        {
            fullName = firstName + " " + lastName;
        }
    }

Optional parameters

Some people say optional parameters are kept in C# to provide common development techniques with other programming languages, but is recommended to concentrate on methods overloading instead of using optional parameters. I am not sure about it, but is good to know how you can use them. Let’s assume we have this method.

string MethodWithOptional(string firstName,  string lastName = "Last name")
{
            return firstName + " " + lastName;
}

In a correct way, it can be called like this.

// Returns "Andre Last name"
this.MethodWithOptional("Andrei");
// Returns "Andre Popescu"
this.MethodWithOptional("Andrei", "Popescu");
// Returns "Andre Popescu" by providing named arguments
this.MethodWithOptional(lastName: "Popescu", firstName: "Andrei")

When you build methods to accept optional parameters, be aware out and ref parameters cannot have a default value and therefore cannot be optional. Also, place optional parameters after non-optional, otherwise your code will throw an error.

// This code will not work
        string MethodWithOptional(string firstName = "First name",  string lastName)
        {
            return firstName + " " + lastName;
        }
Advertisements

Confusing words talking about SharePoint hierarchy

Talking about SharePoint structure can be very confusing. People are talking about site collection, which in the code developers are referencing with SPSite. Nothing wrong until now, just term of “site collection” can be easily confused with SPSiteCollection, which represents all sites in a web application. So, don’t confuse these words. What we called “site collection” is more a “site”.

Another confusion is between site and web. What we called “site” has the equivalent in the code object SPWeb. So is not quite wrong if we consider “site” to be a “web”.

Here is a summary of how SharePoint is organized, starting with web application level.

  1. A web application contains one or multiple sites (we called them “site collections”, but don’t confuse them with SPSiteCollection). If someone is asking you question about this, I recommend you to clarify what he/she is asking about to give correct answer.
  2. Each site, or site collection if you prefer these words, contains at least a web, which is root web or top level site. In the code, you know it by SPWeb, which is the reason I recommend you again to clarify the question if you receive one.
  3. Under the top level site or root web, you can have more webs or sub-sites, which can be organized in a complex hierarchical structure.

In any possible situation you might be, I think is a good idea to clarify questions and terms. Microsoft can be very confusing sometimes, so don’t get caught in terms meaning storm.

Insert data view button is disabled in SharePoint Designer

I work every day with SharePoint Designer, which I consider to be a great tool. But sometimes I discovered insert data view button is disabled.
SPDDisabledButton
If you ask why this is happening, because everything seems to be correct on the content page, I can tell you this is not a SharePoint Designer bug. It is related to ContentPlaceHolderID property. In SharePoint environment, this property is not case sensitive, so the code below is working, even if id of content placeholder is PlaceHolderMain, not PlaceholderMain.

<asp:Content runat="server" ContentPlaceHolderID="PlaceholderMain">

But even if your page is functional, not respecting case sensitivity of ContentPlaceHolderID property can create problems for SharePoint Designer. So, please be sure you respect this and adapt the code accordingly.

<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderMain">

Generate clean HTML in data form web part

A data form web part generated complicated HTML and sometimes creates problem for the designers. When you look into generated HTML you can notice some attributes we don’t want to appear in the markup.

<div style="margin: 0px auto; padding: 0px; width: 800px;" xmlns:ddwrt2="urn:frontpage:internal" xmlns:sharepoint="Microsoft.SharePoint.WebControls" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:x="http://www.w3.org/2001/XMLSchema">

I know you hate them, but I have good news. You can get rid of these very easy. All you need to do is to go to stylesheet declaration and modify value for exclude-result-prefixes like this: ddwrt asp __designer xsl msxsl SharePoint ddwrt2 d x.

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="ddwrt asp __designer xsl msxsl SharePoint ddwrt2 d x" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">

Also, you need to be sure you don’t have namespaces declared on template level. Put all namespaces in stylesheet declaration and remove them, if you have, from template declarations.

I did not try yet, but you probably can apply the same thing to XSLT list view web part, if you customize XSLT, as what I described above is XSLT related. But I leave it up to you to try.

Adding multiple items to a list in a single operation

For each operation you perform on SharePoint list using JavaScript client object model, client context is required to execute query asynchronous operation. But this doesn’t mean is an equal sign between what I have just called it operation and, as an example, each item you want to add to SharePoint list. You can add multiple items to the list and execute client context operation only once.

As in general I like JavaScript organized code, I have created a small file, presented below, which for the moment requires only jQuery to be loaded. There is a plan to extend it and integrate it into a bigger project, but for this example is sufficient to copy the code below only.

/// <Reference Name="MicrosoftAjax.js" />
/// <Reference Path="../jQuery/jquery.js" />



(function () {

    var scriptName = 'SharePoint';


    function execute() {

        Type.registerNamespace('Sys.SharePoint');
        

        Sys.SharePoint.Data = function () {
            /// <summary>Sys.SharePoint.Data static class</summary>
            throw 'Cannot initialize Sys.SharePoint.Data static class';
        }        


        Sys.SharePoint.Data.AddItems = function (listName, listItems, web, success, fail) {
            /// <signature>
            ///     <summary>Add items to the list</summary>
            ///     <param name="listName" type="String" mayBeNull="false" optional="false">List name</param>
            ///     <param name="listItems" type="Array" mayBeNull="false" optional="false" elementType="Object" elementMayBeNull="false">List items</param>
            ///     <param type="SP.Web" mayBeNull="false" optional="true">Web</param>
            /// </signature>
            /// <signature>
            ///     <summary>Add items to the list</summary>
            ///     <param name="listName" type="String" mayBeNull="false" optional="false">List name</param>
            ///     <param name="listItems" type="Array" mayBeNull="false" optional="false" elementType="Object" elementMayBeNull="false">List items</param>
            ///     <param name="web" type="SP.Web" mayBeNull="true" optional="false">Web</param>
            ///     <param name="success" type="Function" mayBeNull="false" optional="false">Success</param>
            ///     <param name="fail" type="Function" mayBeNull="false" optional="true">Fail</param>
            /// </signature>
            var e1 = Function.validateParameters(arguments, [{ name: 'listName', type: String, mayBeNull: false, optional: false },
                                                             { name: 'listItems', type: Array, mayBeNull: false, optional: false, elementType: Object, elementMayBeNull: false },
                                                             { name: 'web', type: SP.Web, mayBeNull: false, optional: true }], true);
            var e2 = Function.validateParameters(arguments, [{ name: 'listName', type: String, mayBeNull: false, optional: false },
                                                             { name: 'listItems', type: Array, mayBeNull: false, optional: false, elementType: Object, elementMayBeNull: false },
                                                             { name: 'web', type: SP.Web, mayBeNull: true, optional: false },
                                                             { name: 'success', type: Function, mayBeNull: false, optional: false },
                                                             { name: 'fail', type: Function, mayBeNull: false, optional: true }], true);
            if (e1 !== null && e2 !== null)
                throw 'Invalid parameters calling AddItems';

            // Define context and web objects for operations
            var ctx = (typeof web === 'undefined' || web === null) ? SP.ClientContext.get_current() : web.get_context();
            var web = (typeof web === 'undefined' || web === null) ? ctx.get_web() : web;

            // Use jQuery deffered for operation
            if (e1 === null && e2 !== null) {
                return Sys.SharePoint.Data._defferedAddItems(listName, listItems, ctx, web);
            }

            // Choose success and fail methods to be executed when operation is ready
            if (e1 !== null && e2 === null) {
                var fail = fail || function (err) { alert(err); };
                Sys.SharePoint.Data._nonDefferedAddItems(listName, listItems, ctx, web, success, fail);
            }

            return null;
        }


        Sys.SharePoint.Data._defferedAddItems = function (listName, listItems, ctx, web) {
            /// <summary>Add items to the list using jQuery deffered (internal use)</summary>
            /// <param name="listName" type="String" mayBeNull="false" optional="false">List name</param>
            /// <param name="listItems" type="Array" mayBeNull="false" optional="false" elementType="Object" elementMayBeNull="false">List items</param>
            /// <param name="ctx" type="SP.ClientContext" mayBeNull="false" optional="false">Context</param>
            /// <param name="web" type="SP.Web" mayBeNull="false" optional="false">Web</param>

            var oList = web.get_lists().getByTitle(listName);
            var deffered = jQuery.Deferred();
            var results = [];


            // for each item of in list items we create item in SharePoint list
            for (var i = 0; i < listItems.length; i++) {

                var listItem = listItems[i];
                var listItemCreationInfo = new SP.ListItemCreationInformation();
                var oListItem = oList.addItem(listItemCreationInfo);

                // for each property of current item, we assign field values
                for (var field in listItem) {
                    oListItem.set_item(field, listItem[field]);
                }

                // update and load SharePoint list item and add it to results array
                oListItem.update();
                ctx.load(oListItem);
                results.push(oListItem);
            }


            // context will execute query async
            ctx.executeQueryAsync(function () {
                deffered.resolve(results);
            }, function (sender, args) {
                deffered.reject(args.get_message());
            });

            return deffered.promise();
        }

        Sys.SharePoint.Data._nonDefferedAddItems = function (listName, listItems, ctx, web, success, fail) {
            /// <summary>Add items to the list (internal use)</summary>
            /// <param name="listName" type="String" mayBeNull="false" optional="false">List name</param>
            /// <param name="listItems" type="Array" mayBeNull="false" optional="false" elementType="Object" elementMayBeNull="false">List items</param>
            /// <param name="ctx" type="SP.ClientContext" mayBeNull="false" optional="true">Context</param>
            /// <param name="web" type="SP.Web" mayBeNull="false" optional="false">Web</param>
            /// <param name="success" type="Function" mayBeNull="false" optional="false">Success</param>   
            /// <param name="fail" type="Function" mayBeNull="false" optional="false">Fail</param>   

            var oList = web.get_lists().getByTitle(listName);
            var results = [];


            // for each item of in list items we create item in SharePoint list
            for (var i = 0; i < listItems.length; i++) {

                var listItem = listItems[i];
                var listItemCreationInfo = new SP.ListItemCreationInformation();
                var oListItem = oList.addItem(listItemCreationInfo);

                // for each property of current item, we assign field values
                for (var field in listItem) {
                    oListItem.set_item(field, listItem[field]);
                }

                // update and load SharePoint list item and add it to results array
                oListItem.update();
                ctx.load(oListItem);
                results.push(oListItem);
            }

            // context will execute query async
            ctx.executeQueryAsync(function () {
                success(results);
            }, function (sender, args) {
                fail(args.get_message());
            });
        }


        Sys.SharePoint.Data.registerClass('Sys.SharePoint.Data');

    }

    

    if (window.Sys && Sys.loader) {
        Sys.loader.registerScript(scriptName, null, execute);
    }
    else {
        execute();
    }


})();

Deffered operation

Let’s take a look at the following example.

	var items = [];
	items.push({ Title: 'Title 1' });
	items.push({ Title: 'Title 2' });
	items.push({ Title: 'Title 3' });
	
	var addItems = Sys.SharePoint.Data.AddItems('List Name', items);
	
	addItems.fail(function(error) {
		alert(fail);
	});
	
	addItems.done(function(results) {
		alert('Success');
	});

You can notice I have used an object for each item I wanted to create and properties have the same name as internal fields. I have add them to an array and pass it as a parameter to Sys.SharePoint.Data.AddItems method. And instead of using classic example, I have used jQuery deffered object to write code easier.

If web parameter is not specified, the web for current context is used. However, it can be specified as additional parameter.

	var context = new SP.ClientContext("https://mydomain.com/sites/toolkit");
	var web = context.get_web();
	
	
	var items = [];
	items.push({ Title: 'Title 13' });
	items.push({ Title: 'Title 12' });
	items.push({ Title: 'Title 10' });
	
	var addItems = Sys.SharePoint.Data.AddItems('List Name', items, web);
	
	addItems.fail(function(error) {
		alert(fail);
	});
	
	addItems.done(function(results) {
		alert('Success');
	});

Classic way

However, you may prefer to use the classic way and pass success and fail callback functions as parameters.

	var context = new SP.ClientContext("https://mydomain.com/sites/toolkit");
	var web = context.get_web();
	
	
	var success = function(results) {
		alert('Operation completed and insert ' + results.length + ' items');
		alert('First item title is ' + results[0].get_item('Title'));
		
	}
	
	
	var fail = function(error) {
		alert(error);
	}
	
	
	var items = [];
	items.push({ Title: 'Title 100' });
	items.push({ Title: 'Title 101' });
	items.push({ Title: 'Title 102' });
	
	Sys.SharePoint.Data.AddItems('List Name', items, web, success, fail);

Conclusion

Sys.SharePoint.Data.AddItems is a method with two signatures. If you want to use jQuery.Deffered object to work with results, you need pass these parameters

  • listName as string and mandatory
  • listItems as array of objects (not null and not optional)
  • web as SP.Web (not null but optional). If not specified, it is considered to be web for current client context.

The second signature accepts five parameters.

  • listName as string and mandatory
  • listItems as array of objects (not null and not optional)
  • web as SP.Web (can be null, but not optional). If not specified, it is considered to be web for current client context.
  • success as function (not null and not optional). It should accept as parameter an array containing created items.
  • fail as function (not null, but optional). It should accept as a parameter a string representing error message.