Skip Ribbon Commands
Skip to main content

Quick Launch

Home
January 09
Building Modular Code

​Having been shown demos of some really impressive reporting technology built using SilverLight, Google maps and BI integration, the client turned around and commented that the development work done so far was too impressive.

In that the developers produced too much functionality.

Getting the demo done took 2 weeks, which in real terms is not a long period of time for this type of complexity. These types of comments tend to get the development firms turning around and rebuilding large portions of the system, this takes even more time, and produces something less functional. This begs the question, why on gods earth would you spend more time, producing a less functional result?

There are two sides of this story, complexity reduction, and re-use of built components. And each has its strengths and weaknesses.

Firstly, developers, specifically smart developers build their code for re-use. Modular components that can be switched out much the same way an engine in a car could be. They just need to be re-wired and all the pipes connected to have the module up and running in a new context. This has a surprising consequence, in that complex functionality can be set up quickly, quicker in fact than scratch building solutions. And because the modules invariably go through large amounts of refinement, tend to be more stable as well.

Developers spend years perfecting these modules, doing more refinement each time the module is re-used. In fact the more a module is used in various solutions, the more refined it becomes. Scratch built code on the other hand has to be refined from scratch as well as built from scratch. On average, scratch built code will go through more change cycles after deployment than modular code, and the result will be more manila, and plain.

There is one big problem with the modular approach. That is complexity.

The developer or the team of developers building these modules are the only ones who really understand the nuances of the code. They understand the reasons for the multitude of delicate subtleties in the code. Any new developer coming in cannot see these nuances, and may actually introduce bugs when modifying things that address these finer points.

Another thing is the rigidity of the requirement, in my experience, if the client takes an approach that enforces delivery of a very specific result, the development time taken to meet the result becomes extended, and re-use of this intellectual property becomes limited. As the client you need to answer a few questions, as you would in any other decision. For instance, if your mechanic fitted a 3 litre engine to your car, but you asked for a 2 litre engine, would that really be a problem? Did you ask for the the 2 litre engine for its fuel consumption, or just because your car needed an engine? You should keep in mind that your mechanic may be a 3 litre engine specialist, and could fit and service your engine best if it is the engine he knows best.

Some of my thoughts around this:

Complexity reduction

  1. Keep in mind that simple means basic, and basic is limited in its scope, reach and functionality.
  2. What does the phrase “Complexity reduction” mean to you? Do you mean it’s simpler to build and maintain? Or that it is simpler and more intelligent from a usability perspective? These two are mutually exclusive.
  3. Complex functionality does not need to be complex, if modules are built and packaged in a “black box” approach; the complex functionality in a module becomes an atomic unit. A solution built using a collection of these complex modules is therefore less complex. 
Information systems are in essence a collection of man-made systems stacked on top of each other. They are massively complex systems when viewed holistically. From the hardware of the servers, all the way up to the interface the user interacts with, the complexity is simply immense. It is only made simpler by taking a modular approach.

Building modular 

  1. Make sure your development contractors, or internal development staff, build modular components as a standard. If you need reports built, build them using reusable reporting modules.
  2. Open a long term engagement with the firms responsible for developing your modules, this way modification to the modules is more successful, and retention of lessons learnt is better.
  3. Protect and re-use your intellectual property, your modules were built for you, and if you followed points 1 and 2, they can be reused and modified. Make use of those facts.
  4. In IT, lessons are hard learnt; make sure your organisation remembers them. Much time and money can be wasted when intellectual property is lost.

 

August 30
Programmatically loop through all Child or Parent ISecurableObjects In SharePoint

On occasion you may wish to loop through each child ISecurableObject, to set permissions on each or set to “un-inherited”. This is made complex because there is no way to easily fetch all the child objects using the standard SharePoint API (on the ISecurableObject object). So you have to code your own loop.
The complexity here is that ISecurableObjects can be of type SPListItem, SPList, SPWebs, or SPSite. This makes the loop complex.
What you ultimately want is something re-usable that you can pass a delegate (or lambda expression), which is executed for each child object found, you want to be able to execute it either against objects with unique permissions or not.

Usage:

 


ISecurableObjectFinder.WithEachChild(web, true, isec=>{

 

   // your code goes here
   System.Console.WriteLine(ISecurableObjectFinder.GetISecurableURL(isec));
});
 
 
In this example, “web” is the ISecurableObject you want to start on, this could be an SPListItem, SPList, SPWeb or SPSite. The Boolean value “true” specifies if the code should execute only against ISecurableObjects with unique permissions.
Alternatively, you may wish to run some code against each parent ISecurableObject, like so.

 
ISecurableObjectFinder.WithEachParent(web, true, isec =>
{
    // your code goes here
    System.Console.WriteLine(ISecurableObjectFinder.GetISecurableURL(isec));
});
 

 

Code:

To do this, you need to build a delegate method:

 
public delegate void WithISecurable(ISecurableObject securableObject);
 

 
And the loop method:
 

 
public static void WithEachChild(ISecurableObject parentObject, bool onlyUnique, WithISecurable code)
            {
 
                if (!onlyUnique || parentObject.HasUniqueRoleAssignments)
                {
                    code(parentObject);
                }
 
                if (parentObject is SPListItem)
                {
                    SPListItem item = (SPListItem)parentObject;
                    if (item.Folder != null)
                    {
                        foreach (SPFile file in item.Folder.Files)
                        {
                            if (file.Item != null)
                            {
                                WithEachChild(file.Item, onlyUnique, code);
                            }
                        }
                        foreach (SPFolder subfolder in item.Folder.SubFolders)
                        {
                            if (subfolder.Item != null)
                            {
                                WithEachChild(subfolder.Item, onlyUnique, code);
                            }
                        }
                    }
                }
                else if (parentObject is SPList)
                {
                    SPList list = (SPList)parentObject;
 
                    if (list is SPDocumentLibrary)
                    {
                        foreach (SPFile file in list.RootFolder.Files)
                        {
                            if (file.Item != null)
                            {
                                WithEachChild(file.Item, onlyUnique, code);
                            }
                        }
                        foreach (SPFolder subfolder in list.RootFolder.SubFolders)
                        {
                            if (subfolder.Item != null)
                            {
                                WithEachChild(subfolder.Item, onlyUnique, code);
                            }
                        }
                    }
                    else
                    {
                        foreach (SPListItem item in list.Items)
                        {
                            if (!onlyUnique || item.HasUniqueRoleAssignments)
                            {
                                code(item);
                            }
                        }
                    }
 
 
                }
                else if (parentObject is SPWeb)
                {
                    SPWeb web = (SPWeb)parentObject;
                    foreach (SPList list in web.Lists)
                    {
                        WithEachChild(list, onlyUnique, code);
                    }
                    foreach (SPWeb subweb in web.Webs)
                    {
                        WithEachChild(subweb, onlyUnique, code);
                    }
                }
            }
 

 
The Parent loop would look like this:

 
public static void WithEachParent(ISecurableObject childObject, bool onlyUnique, WithISecurable code)
            {
              
                ISecurableObject runObject = childObject;
                while (runObject != null)
                {
                    if (runObject.HasUniqueRoleAssignments)
                    {
                        code(runObject);
                    }
 
                    if (runObject is SPListItem)
                    {
                        SPListItem item = (SPListItem)runObject;
                        ISecurableObject parent = null;
                        if (item.File != null)
                        {
                            if (item.File.ParentFolder.Item != null)
                            {
                                parent = item.File.ParentFolder.Item;
                            }
                        }
 
                        if (parent == null)
                        {
                            parent = item.ParentList;
                        }
                        runObject = parent;
                    }
                    else if (runObject is SPList)
                    {
                        SPList item = (SPList)runObject;
                        runObject = item.ParentWeb;
                    }
                    else if (runObject is SPWeb)
                    {
                        SPWeb web = (SPWeb)runObject;
                        runObject = web.ParentWeb;
                    }
 
                }
               

 

            }

 

May 04
Building a Sites or Site Collections

I recently had the requirement to build a web application to host Blog’s needed around the organisation. Basically the organisation was asking for blogs created in one of their farms around the world to be branded in a consistent way, and for any new blogs to be added to a central registry so that they can be seen in a single list containing all the blogs.

The idea was to have a web application created on each of the regional farms, which hosted one or more Site Collections each containing one or more Blog Sites.
 
I’m not going to go into detail as to how the registry was built, but in brief a feature is used which connects to a central web service and registers the blog which is added to a list, and displayed to the Users by way of a web part.
 
Generally in these situations there are two approaches with regards to how the Web Application is structured, each with pro’s and con’s.
 
New Blogs could be created as new Site Collections
  1. Advantages
    1. Separate content databases (this helps by keeping the sizes of your Content databases to manageable levels)
    2. Site Collections are more isolated, so the blog owner can manage his own groups and go mad doing whatever he likes without affecting other blogs.
    3.  

  2. Disadvantages
    1. Navigation (top navigation and quick launch navigation) is unique, custom development needs to be done to overcome this.
    2. Branding changes need to be applied to each site collection (for master pages and CSS style sheets) this means that once you have a large amount of blogs, doing branding changes is difficult.

 

New Blogs could be created as new Sites in a single Site Collection containing all Blogs
  1. Advantages
    1. Navigation (top navigation and quick launch navigation) can be shared if needed out-of-the-box without the need for custom development.
    2. Branding changes need to be applied to the single site collection easily, this means that even if  you have a large amount of blogs, branding changes can be applied to a single place.
  2. Disadvantages
    1. Single Content Database which could get large to the stage of being un-manageable.
    2. SharePoint Groups are shared between sites in the site collection, which means if a user changes the members of a Group used by another site, there may be un-foreseen and un-wanted repercussions.

Given the option, I would suggest a combination of the two. So try to get the best of both worlds (or a reasonable compromise). If you segment your Blogs into separate site collections according to the strengths and weaknesses of both approaches, you have the optimal configuration.

Some things to consider:
 
Split Site collections where the following is needed (or may be needed)
  1. Where separate Branding may be needed
  2. Where the splitting of Content Databases may be needed, if the case of site collections which may contain a large number of sites.
Share Site Collections where the following is needed (or may be needed)
  1. Where Shared Branding is needed by all sites concerned.
  2. Where Shared Navigation is required between all sites
  3. Where Shared Groups of users are needed

By this we can extrapolate that the most optimal setup would probably group sites into separate Site Collections by one of the following criteria.

  1. Topical Classification (so perhaps things like Engineering, Management or Operations)
  2. Department (so perhaps Sales, Help desk or Information Management)
  3. Geographical Region (so something like Cape Town and London)
 
 

 

April 29
SharePoint 2010 + WCF + AJAX

Ok, so I’ve been working with some of the .NET 3.5 functionality in SharePoint 2010, some of this functionality has been difficult to implement. The idea is to use the AJAX functionality, together with the WCF capabilities for client integration in SharePoint, for now this will include JavaScript client side proxies for services (Service Reference in the AJAX Script Manager). We need a few things to get this to function.

  1. The AJAX ScriptManager must be added to the page.
  2. To be used by the AJAX ScriptManager, the WCF service needs to use the enableWebScript web.config option (or WebScriptEnablingBehavior class added to the endpoint)
JavaScript proxy generation is an extremely useful function of the AJAX toolkit in .NET. Using WCF and a ScriptManager, you can get things rolling without having to worry about generating soap request envelopes yourself, dealing with the XHTTPRequest object in JavaScript, and parsing JSON results.  Everything is done for you.
 
In fact if you use Data Contracts in the responses from your services, the Object will be serialized, transported and de-serialized automatically, you’ll just be able to access the object properties using JavaScript.
To keep things simple you should consider the following:
  1. You don’t want to be making changes to MasterPages in order to get the AJAX ScriptManager added to the page, you should register it on all pages when a feature is activated. This will allow you to disable it if needed.
  2. You don’t want to have to mess around with web.config settings for the WCF service, you should use a factory class to pre-configure the service.
So the first thing we are going to look at is the ScriptManager, we will create a delegate control which adds a ScriptManager  to the page if it doesn’t already exist, the delegate control will also register the WCF Service we create with the script manager as well as any other CSS/JavaScript files you’ll need.


It’ll look something like this (can’t take credit for this code comnpletely, it’s based on something I found some time back and unable to find at the moment), it is attached to the AdditionalPageHead delegate by a feature.

 
public class MyDelegate : WebControl
    {
        public static String ControllerFileName = "Controller.js";
       
 
        protected override void OnInit(EventArgs e)
        {
            Page.Init += delegate(object sender, EventArgs e_Init)
            {
                if (ScriptManager.GetCurrent(Page) == null)
                {
                    ScriptManager sMgr = new ScriptManager();
                    Page.Form.Controls.AddAt(0, sMgr);
                }
 
                if (ScriptManager.GetCurrent(Page) != null)
                {
                    // build reference to Service Script
                    String url = SPContext.Current.Web.Url;
                    if(!url.EndsWith("/")) url += "/";
                    Uri service = new Uri(new Uri(url),"_vti_bin/MyService/MyService.svc");
                    ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(service.ToString()));
 
                    // register scripts
                    ClientScriptManager csm = this.Page.ClientScript;
 
                   
                    if (!csm.IsClientScriptIncludeRegistered(ControllerFileName))
                    {
                        csm.RegisterClientScriptInclude(ControllerFileName, this.ResolveClientUrl("/_layouts/MyService/" + ControllerFileName));
                        csm.RegisterClientScriptBlock(typeof(CheckInNotifyDelegate), "CSS", "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + this.ResolveClientUrl("/MyService/Styles.css") + "\"/>"); 
                    }
                }
            };
            base.OnInit(e);
        }
 
This causes the ScriptManager to be added the Controls collection on the Page.Init event, this is the correct place in the rendering life cycle of ASP.NET to modify the Controls collection.
The Feature can then contain a delegate control which is added to the AdditionalPageHead delegate.The element manifest will look something like this.
 
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead" Sequence="50" ControlClass="MyAssembly.MyDelegate" ControlAssembly="$SharePoint.Project.AssemblyFullName$"/>
</Elements>
 
The Control itself basically adds the ScriptManager to the page (if one doesn't exist already) registers the service with the Script Manager, creates a reference to a controller JavaScript file on the page (which would contain any logic needed to process the results of the service invocation).
What I normally do for any style sheets, is ghost them in the content database, it makes customization of the style sheets easier without having to re-deploy the solution file.
I would recommend you try use XSLT where you can, because it can be ghosted in the content database, and then easily modified if format tweaks are needed. You can easily serialize DataContracts into XML for processing against XSLT.
The next thing is the WCF Service. SharePoint has factory classes which provision the service to handle the detail around things like authentication (Claims based authentication for instance). This removes the need for customised web.config entries or custom code to handle the complexities around this. The Service Host is configured automatically. This is a great help. These are the options.
 
Service Type
Service Factory
Description
SOAP service
MultipleBaseAddressBasicHttpBindingServiceHostFactory
Basic HTTP binding must be used, which creates endpoints for a service based on the basic HTTP binding.
REST Service
MultipleBaseAddressWebServiceHostFactory
The service factory creates endpoints with web bindings.
ADO.NET Data Service
MultipleBaseAddressDataServiceHostFactory
A data service host factory can be used.
 
To make use of one of these you .svc file would look something like this.
 
<%@ ServiceHost Language="C#"
    Service="MyAssembly.MyService,
        $SharePoint.Project.AssemblyFullName$"     Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory,
Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
"%>
 
None of these options however support the enableWebScripts behaviour on the end points. The enableWebScripts behaviour (or WebScriptEnablingBehavior class) is used by the AJAX framework, and allows the service to return a service proxy in javascript when “/js” or “/jsdebug” is added to the URL of the service.
The Service Host Factory classes in SharePoint do however set things up like Claims Based Authentication, or whatever authentication method you are using on the site automatically. What we want is a service host that does both, it configures the service host based according to SharePoint, and automatically adds the enableWebScripts behaviour to the endpoints.
 
Luckily we can build our own service hosts and service host factories. All we need is a custom class for the service host and a custom class for the factory class. We extend the REST based SharePoint Service Host, we will need to remove any end point behaviours that are there already, and add the enableWebScript behaviour.
 
That will be done in the custom service host, but first we need to build our own service host factory class, also extending the REST based SharePoint factory class.
 
   public class MyServiceHostFactory : Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory
    {
 
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost (serviceType, baseAddresses);
        }
 
 
    }
 
Then we extend the MultipleBaseAddressWebServiceHost class and modify the behaviours when the service host is opened.
 
public class MyServiceHost  : Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHost
    {
 
        public MyServiceHost (Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
            {
            }
     
        protected override void OnOpening()
        {
            base.OnOpening();
           
            foreach (ServiceEndpoint endpoint in base.Description.Endpoints)
            {
                if (((endpoint.Binding != null) && (endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>() != null)) && (endpoint.Behaviors.Find<WebScriptEnablingBehavior>() == null))
                {
                    // try remove any previous behaviours
                    while (endpoint.Behaviors.Count > 0)
                    {
                        endpoint.Behaviors.RemoveAt(0);
                    }
                    endpoint.Behaviors.Add(new WebScriptEnablingBehavior());
                }
               
            }
 
 
            ServiceDebugBehavior debug = this.Description.Behaviors.Find<ServiceDebugBehavior>(); 
            // if not found - add behavior with setting turned on 
            if (debug == null) {    
                this.Description.Behaviors.Add(         
                    new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true }); }
            else {      
                // make sure setting is turned ON    
                if (!debug.IncludeExceptionDetailInFaults)    
                {        
                    debug.IncludeExceptionDetailInFaults = true;    
                }
            }
 
            ServiceMetadataBehavior metadata = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
            // if not found - add behavior with setting turned on 
            if (metadata == null)
            {
                this.Description.Behaviors.Add(
                    new ServiceMetadataBehavior() { HttpGetEnabled = true });
            }
            else
            {
                // make sure setting is turned ON    
                if (!metadata.HttpGetEnabled)
                {
                    metadata.HttpGetEnabled = true;
                }
            }
 
        }
 
 
    }
 
This also sets some service behaviours as well to enable debugging and metadata.
So now your SVC file can look like this.
 
<%@ ServiceHost Language="C#"
    Service="MyAssembly.MyService,
        $SharePoint.Project.AssemblyFullName$"
    Factory=" MyAssembly.MyServiceHostFactory, $SharePoint.Project.AssemblyFullName$"%>
 
Now when you load up your service with the “/js” or “/jsdebug” added to the URL you’ll get a JavaScript Service Proxy that the script manager will use.
 
One last thing, the Interface for the service should have the correct serialization attributes. These will ensure that your service functions when accessed via the AJAX Service Proxy class. The Service Interface Class would look something like this.
 
[ServiceContract(Namespace="", Name="MyService")]
        public interface IMyService
        {
 
            [OperationContract]
            [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat=WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]
            string GetMyParameter(String Option1, String Option2);
 
 
        }
 Just for completeness I’ll include the implementation of the service as well.
 
    [ServiceBehavior(Namespace="MyService")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class MyService : IMyService
    {
        public string GetMyParameter(String Option1, String Option2)
        {
              return "This Worked!!!";
        }
    }
 
 
 
 

 

March 23
Automating Solution Deployment

 

While busy building the deployment process for the latest project I’m busy on, I built a deployment console application which does a whole bunch of provisioning, it’s built in c#. Here is my code to deploy a set of new solution files.

 

the Following code exports solution files deployed to the specified webApplication (from the config database)

                    using (SPSite site = new SPSite(webAppURL))
                    {
                        using (SPWeb web = site.OpenWeb())
                        {

                            // Solutions

                            foreach (SPSolution sol in SPFarm.Local.Solutions)
                            {


                                Console.WriteLine(sol.Name);

                                try
                                {
                                    if (sol.ContainsWebApplicationResource)
                                    {
                                        foreach (SPWebApplication webapp in sol.DeployedWebApplications)
                                        {
                                            if (webapp.Id == site.WebApplication.Id)
                                            {
                                                sol.SolutionFile.SaveAs(targetDirectory + "\\SolutionFiles\\" + sol.Name);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        sol.SolutionFile.SaveAs(targetDirectory + "\\SolutionFiles\\" + sol.Name);
                                    }
                                }
                                catch (Exception er)
                                {
                                    sol.SolutionFile.SaveAs(targetDirectory + "\\SolutionFiles\\" + sol.Name);
                                    Console.WriteLine(er.Message);
                                    Console.WriteLine(er.StackTrace);
                                }
                            }

                        }
                    } 

The following code waits for all solution deployment timer jobs to complete.

        public static void WaitForDeploymentJobs()
        {
            bool jobsRunning = true;
            while (jobsRunning)
            {
                jobsRunning = false;
                Console.Clear();
                Console.WriteLine("Waiting for deployment Jobs to finish...");
                foreach (SPService service in SPFarm.Local.Services)
                {

                    foreach (SPJobDefinition jobDefinition in service.JobDefinitions)
                    {
                        //Console.WriteLine(jobDefinition.Name);
                        if (jobDefinition.GetType().FullName == "Microsoft.SharePoint.Administration.SPSolutionDeploymentJobDefinition")
                        {

                            Console.WriteLine(jobDefinition.Name);

                            jobsRunning = true;
                        }
                    }
                }
                Thread.Sleep(1000);
            }
        }


 


 

 

The following code deploys or upgrades all solution files found in a specific directory to a web application

                        using (SPSite site = new SPSite(webAppURL))
                        {
                            using (SPWeb web = site.OpenWeb())
                            {


                                foreach (FileInfo file in soldir.GetFiles())
                                {
                                    try
                                    {
                                        SPSolution foundSolution = null;



                                        foreach (SPSolution sol in SPFarm.Local.Solutions)
                                        {
                                            if (sol.Name == file.Name)
                                            {
                                                foundSolution = sol;
                                            }
                                        }

                                        if (foundSolution != null)
                                        {
                                            try
                                            {
                                                Console.WriteLine("    Upgrading " + file.Name);
                                                foundSolution.Upgrade(file.FullName);
                                            }
                                            catch (Exception er)
                                            {
                                                Console.WriteLine("    SOLUTION UPGRADE WARNING: " + er.Message);
                                            }
                                        }
                                        else
                                        {
                                            Console.WriteLine("    Adding " + file.Name);
                                            foundSolution = SPFarm.Local.Solutions.Add(file.FullName);
                                        }

                                        bool deployed = foundSolution.Deployed;

                                        if (deployed)
                                        {
                                            if (foundSolution.ContainsWebApplicationResource)
                                            {
                                                deployed = false;
                                                // check if deployed to web application...
                                                try
                                                {
                                                    foreach (SPWebApplication webapp in foundSolution.DeployedWebApplications)
                                                    {
                                                        if (webapp.Id == site.WebApplication.Id)
                                                        {
                                                            deployed = true;
                                                        }
                                                    }

                                                }
                                                catch (Exception er)
                                                {
                                                    Console.WriteLine(er.Message);
                                                    Console.WriteLine(er.StackTrace);
                                                }
                                            }
                                        }

                                        if (!deployed)
                                        {
                                            try
                                            {
                                                if (!foundSolution.ContainsWebApplicationResource)
                                                {
                                                    Console.WriteLine("    Deploying " + file.Name);
                                                    foundSolution.Deploy(DateTime.Now, true, true);
                                                }
                                                else
                                                {
                                                    Console.WriteLine("    Deploying " + file.Name + " to " + site.Url);
                                                    Collection<SPWebApplication> webapps = new Collection<SPWebApplication>();
                                                    webapps.Add(site.WebApplication);
                                                    foundSolution.Deploy(DateTime.Now, true, webapps, true);
                                                }

                                            }
                                            catch (Exception er)
                                            {
                                                Console.WriteLine(er.Message);
                                                Console.WriteLine(er.StackTrace);
                                            }
                                        }
                                    }
                                    catch (Exception er)
                                    {
                                        Console.WriteLine(er.Message);
                                        Console.WriteLine(er.StackTrace);
                                    }
                                }



                            }
March 11
Tame the CSS Beast

I’ve been doing a shed load of branding and re-styling work over the last couple weeks (in fact I’m getting pretty tiered of it all by now), this is CSS changes by the ton, the enterprise I’m doing this for has a ton of IE 6 machines as well, so the CSS selectors I’m able to get at are limited. Here are some tips I’ve picked up along the way.

  1. Stay away from margins if at all possible. Using these incorrectly (in conjunction with percentage widths) will cause content to disappear under other parts of the page. Target the parent element rather and set its padding.
  2. This may seem obvious to some, but the importance of a style is defined by the specificity of the selector, for instance “BODY input.HighPriorityButton” will override “input.HighPriorityButton”, regardless if these two styles are in different style sheets or in fact the order of these style sheets in the HTML. You can use this fact to your advantage because it overrides styles regardless of where the style sheet link appears in the HTML.
  3. Modify the source HTML rather than using highly complex selectors. I know people use complex JQuery or CSS3 selectors to get something done, rather than just classing things correctly. This could (and often does) result in the wrong element being styled.  Wrapping an element in a div tag and classing the div tag allows you to target the correct elements more accurately, and will isolate its the effect (so that it doesn’t break some other style).
  4. Name your Classes according to function or type rather than style, ultimately your class name should represent the type or function of the element rather than the style itself. So use something like “EditSettingsSubmitButton” rather than “BlueButton”.
  5.  I will also recommend that you try to get the least complex solution to achieve the desired result. Keeping in mind that you will want to re-use your HTML code as easily as possible. As an example you could have a Form classed as “EditSettingsForm” and the submit button classed as “SubmitButton”. Doing things this way will allow you to target a specific button using the selector “form.EditSettingsForm input.SubmitButton” but you can also target ”SubmitButton” buttons, doing things this way allows you to target things specifically as well as generically.
  6. Another thing I noticed, is that Internet Explorer 6 does not support the direct child selector, so the selector “div.SomeClass > div.SomeOtherClass” will not function in IE 6.
     
  7. DO NOT USE INLINE STYLES, AT ALL EVER. You will regret it.

 Keeping everything in check on a large site with a large amount of variety is complex to say the least. You need to ensure that your style changes do not apply to the wrong element, but you also want to be able to change something globally without the need to change several hundred styles. Getting this right relies on a consistent, comprehensive approach to classing your elements in HTML as well as using the right selectors in CSS. Doing this correctly will lower maintenance and ease future development.

March 09
Kingston SSDNow 512GB SSD

ShowImageCA4V7JQ5.jpgRunning a Windows Server 2008 R2 virtual machine through VMWare on a host operating system takes a lot of resources, if fact whatever resources you have R2 will consume them. The Laptop I use at clients is a Intel Core I7 (740QM) based Alienware m15X. And although the CPU is not top of the range, it’s no slouch. I equipped it with it’s maximum for memory (because it only has 2 memory slots, it’s 8GB, which again is not optimal). I’ve been running on a128gb SuperTalent SSD since I got the laptop. And I’m running out of space continuously. I have 2 Virtual machines one for MOSS 2007 and one

for MOSS 2010. They consume massive amounts of space on the drive. I feel the need to upgrade.

What I found is a Kingston SSDNow V100 256GB SSD, which I found on www.nivo.co.za. For around R4700. So I purchased it and am going to collect later today. Of course as these things are, WantItAll has a Samsung 470 series SSD (also 256GB) which delivers better speed all round (about 30% more performance which is substantial). On the WantItAll website it’s available for about R500 more, 10% more cost, 30% more performance. I’m currently kicking myself. But hey, these drives are expensive, and the Kinston drive is one of the cheapest in the market. The drive will still get around 230 mb / sec read speeds, 180mb write speeds and near zero seek times.
 
Time to collect the drive, clone my existing drive and take the thing for a spin.

January 31
Follow the Linq's

I enjoy tying to figure out how some technology works, I’ve been playing around with Linq, the Entity framework, Lambda expressions, and anonymous types recently.  These are actually all Linq related technologies, and whereas I know these are “so 2 years ago” SharePoint 2010 has recently gained Linq functionality (Linq to SharePoint) so it’s currently important for me to look into these technologies.

To overview Lambda Expressions are an extension of delegates, they effectively allow you to define anonymous functions in your code using a type of short hand. You can define function parameters and code to execute by using a simple format.
 
var lambdaFunction = spweb => {spweb.Title=’Something’; spweb.Update();}
lambdaFunction(spweb)
 
The impressive part about lambda functions is that they can be inspected through code, so the execution of the function does not need to happen in .NET, the function could perhaps be translated to SQL for instance, simply because the logic in the lambda function can be reflected.
 
This is a neat trick.

 

Anonymous types are declared inline,

 
var obj = new {Variable1 = spweb.Title}
 
The impressive part about this is that the compiler knows the type and considers it type safe.
The IDE recognises the anonymous type and it supports code completion on it.

 

From what I understand about Linq, is that it extends this functionality to generate lambda Expressions and anonymous types based on a query language.
 
All three of these technologies are “Compile time” technologies. And equate to a form of short hand. Simplifying things greatly.
 
They have also made me think the need to be able to reflect against the process of functions, the internal execution sequence inside each method. It makes me wonder if it would ever be possible to do more with this type of technology.  

 

Currently they could take the expression graph for a method and convert aspects of it at least to an SQL statement, farming off the logic to an external system that speaks a different language (that could probably do the job much better or quicker). Would it be possible to package segments of logic and run them on a more appropriate sub systems? Imagine for instance writing logic in c# having it converted to JavaScript, and executing on a web browser.

 

 

 About this blog

 
About this blog
Andrew Kinnear is a SharePoint focussed Development specialist, and Radio Controlled Aircraft enthusiast. These are his random ramblings.