Wednesday, April 17, 2013

XMLNodeReader problem: The specified type was not recognized



// Solves the "The specified type was not recognized: name='##', namespace='##', at ..."
    // Came across this when trying to serialize an object of a custom type
    // It is caused due to a missing namespace reference (for some reason, the LookupNamespace method in the reader
    // does not return a string from the NameTable)
    public class XmlNodeReader2 : XmlNodeReader
    {
        public XmlNodeReader2(XmlNode node)
            : base(node)
        {
        }

        public override string LookupNamespace(string prefix)
        {
            return NameTable.Add(base.LookupNamespace(prefix));
        }

        
    }

source:http://coderstuff.blogspot.nl/2005/10/xmlserializer-bug-when-xsitype-is-used.html

Tuesday, February 19, 2013

Retrieving a resource key in a custom LayoutsPageBase page used in SP2010

1. Create the following property in your aspx.cs file:




protected Type ResourceType
{
     get
     {
          return typeof(MyResources); // replace 'MyResources' with your own resources file
     }
}




2. Create the following method which will return the requested value stored in the .resx file by looking up the resource key



protected string GetResourceString(Type resourceType, string resourceKey)
{
     return SPUtility.GetLocalizedString(string.Format("$Resources:{0}, {1}", resourceType.Name, resourceKey), resourceType.FullName, getLanguage);
}


3. Good to go. Say you would need to populate a label in the Page_Load event with a string stored in the resources file with a key called 'MyLabelText'; you can then achieve this as follows:



protected void Page_Load(object sender, EventArgs e)
{
     lblMyLabel.Text = GetSourceString(ResourceType, "MyLabelText");
}

Thursday, February 14, 2013

How to refresh parent page after closing a SP.UI.ModalDialog

var options = {
 
url:'/_layouts/YourAspx/YourPage.aspx',
 title: 'Your Application Page Title',
 allowMaximize: false,
 showClose: true,
 width: 700,
 height: 260,
 dialogReturnValueCallback: RefreshOnDialogClose
 };
SP.UI.ModalDialog.showModalDialog(options);


Key here is the callback function; set it to RefreshOnDialogClose. Dead simple ;-)

Monday, December 3, 2012

How to display live server side processing/messages in a browser

How to display live server side processing/messages in browser.

Use this in case the webpart/application invokes a long running processes. This way the user will continuously be updated on the progression of code execution. In my particular case I'm using a textbox to pass messages onto but feel free to replace it with any other type of control, such as a progression bar. You can make it as fancy as you want, sky's the limit. The trick is to create an iframe, in which you embed the application page that actually calls the long running process. So you'll need a few things here

- A parent .aspx page with a textbox ('txtLogs')
- An 'child' .aspx page ('LongRunningOp.aspx') which will execute the code. The page itself will not contain any controls, just code behind
- An iframe to embed that child .aspx within the parent page
- An update function to update the textbox, which will be called through the child .aspx page

Creating the iframe will be accomplished by using the following piece of code

function BeginLongRunningOp() {

       var iframe = document.createElement("iframe");

       // set the source to the .aspx, in this example it can be found in the layouts folder of the 14
       // hyve as i created this for a SP2010 webpart
       iframe.src = "/_layouts/CodingNCrap/LongRunningOp.aspx";
       iframe.style.display = "none";
       document.body.appendChild(iframe);
}

Calling this function from the parent page will open the child page and start the execution. You will also need an additional function to update the textbox as code is execution:

function UpdateProgress(Message) {
       var logWindow = document.getElementById('<%= txtLogs.ClientID %>');
       logWindow.value = logWindow.value + Message;
}

Last thing needed to make this work is to go to the code of the child .aspx page and add the following line to your method that will make the update:

protected void UpdateProgress(string Message)
{
       try
       {
              Response.Write(String.Format("< script>parent.UpdateProgress({0});< / script>", Message));
       }

       catch (Exception exc)
       {
              // your exception handling logics here
       }
}







Monday, October 22, 2012

Finding site column used anywhere in your web application

Little powershell script to find out where your fields are currently being used in the web app

$solutionWebApplication = "http://yourSPurl/"
$fieldTitle = "ActiveConfig"    #DisplayName
$fieldGroup = "Custom Columns"
$spAssigment = Start-SPAssignment    #Use to dispose SPWeb safely
$spWeb = Get-SPWeb $solutionWebApplication -AssignmentCollection $spAssignment     #Get SPWeb Instance
foreach ($field in $web.AvailableFields)
{
 if($field.Group -eq $fieldGroup -and $field.Title -eq $fieldTitle)
 {
  $field.ListsFieldUsedIn() | ForEach-Object {
   $web = $site.AllWebs[$_.WebID]
   $list = $web.Lists[$_.ListID]
   Write-Host "Web:" $web.Title " | List:" $list.Title " | ListUrl:" $list.RootFolder.Url " | StaticName:" $field.StaticName " | FieldID:" $field.ID
  }
 }
}

Tuesday, October 16, 2012

Finding site column used in content type by querying content db

Exception calling "Delete" with "0" argument(s): "Site columns which are included in content types or on lists cannot be deleted. Please remove all instances of this site column pri
or to deleting it."


ughh..

there are myriad approaches to hunt down that damn column, for example by using powershell. here is an alternative, directly querying the content db


SELECT
     ct.ContentTypeId            [ContentType ID]
,    Definition                  [ContentType Definition]    
,    ct.DeleteTransactionId      [ContentType DeleteTransaction]
,    ctu.ListId                  [List GUID using CT]
,    l.tp_Created                [List Creation Date]
,    tp_DeleteTransactionId      [List DeleteTransaction]
,    tp_FeatureId                [Feature GUID]
FROM
     ContentTypeUsage             ctu
     INNER JOIN dbo.Webs          w  ON ctu.WebId         = w.Id
     INNER JOIN dbo.AllLists      l  ON ctu.ListId        = l.tp_ID
     INNER JOIN dbo.ContentTypes  ct ON ct.ContentTypeId  = ctu.ContentTypeId
WHERE
     ct.Definition LIKE '%your column%'     

Friday, August 17, 2012

Splitting key-value string using LINQ

Time has come to get down-and-dirty with LINQ! For an app i'm building, i need to store an array of key/value pairs in a single string. It consists of an ID and a folder path, which are separated by use of a semicolon delimiter. The actual pairs are then separated using a pipe. Here is an example:



string folders = @"32;c:\|48;c:\code|52;c:\program files|";

I created the following method that returns a Dictionary object:



        public static Dictionary<int, string> GetFolders(string folders)
        {
            string[] x = folders.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); // first retrieve a string array of all the pairs

            return x.ToDictionary(y => Convert.ToInt32(y.Split(';')[0]), y => y.Split(';')[1]); // second stage of splitting
        }

Here's a full working console example:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string folders = @"30;c:\|48;c:\code|99;c:\Program Files";
            Dictionary<int, string> KeyValuePairs = GetFolders(folders);
            foreach (KeyValuePair<int, string> pair in KeyValuePairs)
            {
                Console.WriteLine("Key: '" + pair.Key + "', Value: '" + pair.Value + "'");
            }
            Console.ReadKey();

            /* Results:
             * 
             * Key: '30', Value: 'c:\'
             * Key: '48', Value: 'c:\code'
             * Key: '99', Value: 'c:\Program Files'
            */
        }

        public static Dictionary<int, string> GetFolders(string folders)
        {
            string[] x = folders.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); // first retrieve a string array of all the pairs

            return x.ToDictionary(y => Convert.ToInt32(y.Split(';')[0]), y => y.Split(';')[1]); // second stage of splitting
        }
    }
}