Programmatically Activating SharePoint Features
14. June 2011 03:38

SharePoint features can exist at several different scopes, including Web, Site, and Web Application.  Each of these can be activated and deactivated programmatically, but they have to be handled slightly differently.

 

This can be extremely useful for automated deployment tools, or any number of other purposes.

 

Given a WebApplication scoped feature, you’ll need an SPWebApplication object (which you can get from the property on your SPSite object if needed):

 

For example, if you wanted a method which could activate a WebApplication scoped feature, an optionally deactivate and reactivate (useful after upgrading the feature during a deployment):

 

        private void ActivateWebApplicationFeature(SPWebApplication WebApplication, Guid FeatureGuid, bool Reactivate)
        {
            if (Reactivate)
            {
                try
                {
                    //Attempt to deactivate feature.  Will fail if already deactivate.
                    WebApplication.Features.Remove(FeatureGuid, true);
                }
                catch
                {
                    //Was not activated, or could not be deactivated.
                }
            }

            //Now activate
            WebApplication.Features.Add(FeatureGuid);
        }
 

For a feature scoped at the Site level, you simply leverage the SPSite object

{SPSite}.Features.Add(FeatureGuid);

{SPSite}.Features.Remove(FeatureGuid, true);

 

And for the Web scoped features, of course, just use the SPWeb

{SPWeb}.Features.Add(FeatureGuid);

{SPWeb}.Features.Remove(FeatureGuid, true);

 

The boolean on the remove indicates whether to force deactivation.  Note that if the feature ID can not be found, permissions are not available, or it is already in the requested state, you will get a failure – So be sure to wrap your code with the appropriate error handling.

Tags: Comments (0) | Permalink
SharePoint Designer Zip/Compress Workflow Action Deployed in a Sandboxed Solution
31. May 2011 07:41

Whew, that was a long title – But I think you’ll find this very useful.  Some notes on deploying a custom workflow action that you can use inside of SharePoint designer, which will Zip attachments to list items and deposit the compressed file in a document library – and it is all deployed in a sandboxed solution, so you can use it on hosted SharePoint Foundation instances.  In this case, I even generate PDF files with the data from the list items, and include them in the compressed file.  Great for archival or offsite storage.

 

First of all, this MSDN article about general workflow actions and sandboxed solutions will help you immensely with the basics:

http://msdn.microsoft.com/en-us/library/gg615449.aspx

Next you’ll want to grab a copy of:

  • SharpZipLib (an open source compression library)
  • SharpPDF (if you want to generate PDF’s too)

You’ll want to get the source to each, as we’ll upgrade them to .net 4.0, and build them as signed assemblies.

 

Make yourself a SharePoint solution in Visual Studio per the MSDN article above, and add two (or one if you are leaving out the PDF bits) existing projects using the source of the libraries (SharpZip, SharpPDF). 

  • You’ll need to let the upgrade wizard upgrade them to .net 4.
  • Check the project settings on them and make sure they are targeting the .net 4 framework (AnyCPU)
  • For SharpPDF you’ll need to open the AssemblyInfo.cs file and add a line to the bottom
[assembly: AllowPartiallyTrustedCallers()]

 

In my case, I’m always looking at a single list, so my workflow action only accepts a ListItemID.  You’ll probably want to make that more generic by adding a few more parameters to your Action.  Again, these custom actions are described in plenty of detail in the MSDN article referenced above.

 

       public static Hashtable Package(SPUserCodeWorkflowContext context, string ItemID)
        {
            Hashtable result = new Hashtable();

            try
            {
                result["Result"] = PackageListItem(closingId, context.CurrentWebUrl);
            }
            catch (Exception e)
            {
                result["Result"] = "ERROR" + e.ToString();
            }

            return result;
        }

 

Where the PackageListItem method looks like this:

 

        public static string PackageListItem(string ItemID, string webUrl)
        {
            SortedList<string, byte[]> files = new SortedList<string,byte[]>();
            
            using (SPSite site = new SPSite(webUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    //Find the list item
                    SPListItem item = web.Lists["List"].GetItemById(int.Parse(ItemID));

                    //Create a PDF of the list item data and add it to the 
                    //  compressed files collection
                    files.Add("ListData.pdf", CreateDocument(item, "Title"));

                    //Loop through all list item attachments
                    //  and add them to the compressed file collection
                    foreach (string attachment in item.Attachments)
                    {
                        SPFile attFile = web.GetFile(item.Attachments.UrlPrefix + attachment);
                        files.Add(attachment, attFile.OpenBinary());
                    }
                    
                    //Zip everything up and finish!
                    byte[] package = CreateZip(files);

                    files = null;

                    web.AllowUnsafeUpdates = true;

                    //Add the zipped package to a doc lib
                    SPFile file = web.Folders["Archive"].Files.Add(
                        string.Format("({0})_{1}.zip", 
                        ItemID, 
                        DateTime.Now.ToString("yyyy'-'MM'-'dd HH''mm''ss")), 
                        package);

                    web.Update();

                    file.Update();

                    web.AllowUnsafeUpdates = false;

                    package = null;

                    //return the List Item ID of the generated file to the workflow
                    return file.ListItemAllFields["ID"].ToString();

                }
            }
        }

 

And create document, if you are interested in generating PDF’s, looks like this.  I do some hackery to leave out boring version and guid fields from the list data – feel free to do something more intelligent:

 

 

 public static byte[] CreateDocument(SPListItem item, string type)
        {
            pdfDocument pdf = new pdfDocument(type, "Some Text");
            pdfPage page = pdf.addPage();

            page.addText(item["Title"].ToString(), 20, 730, pdf.getFontReference(predefinedFont.csHelvetica), 12);

            pdfTable table = new pdfTable(pdf, 1, pdfColor.Black);
            table.borderSize = 1;
            table.borderColor = pdfColor.Black;
            table.coordX = 50;
            table.coordY = 690;


            table.tableHeader.addColumn(150);
            table.tableHeader.addColumn(300);

            foreach (SPField f in item.Fields)
            {
                if (f.Type != SPFieldType.Guid && !f.Title.ToLower().Contains("version") && !f.Title.Contains("Title"))
                {
                    try
                    {
                        pdfTableRow row = table.createRow();
                        row[0].addText(f.Title);
                        row[1].addText(item[f.InternalName].ToString());
                        table.addRow(row);
                    }
                    catch { }
                }
            }
            
            page.addTable(table);

            MemoryStream ms = new MemoryStream();
            pdf.createPDF(ms);

            return ms.ToArray();
        }

 

The CreateZip method called in package is also very simple:

 

 public static byte[] CreateZip(SortedList<string, byte[]> files)
        {

            MemoryStream ms = new MemoryStream();

            using (ZipOutputStream s = new ZipOutputStream(ms))
            {

                s.SetLevel(5); // 0 - store only to 9 - means best compression

                foreach (string file in files.Keys)
                {

                    // Using GetFileName makes the result compatible with XP
                    // as the resulting path is not absolute.
                    ZipEntry entry = new ZipEntry(file);

                    // Could also use the last write time or similar for the file.
                    entry.DateTime = DateTime.Now;
                    s.PutNextEntry(entry);

                    s.Write(files[file], 0, files[file].Length);                    
                }

            }

            return ms.ToArray();

        }

This is relatively resource intensive of course, and will use some of your sandboxed resources.  It hasn’t been a problem for me, but your mileage may vary.

Tags: Comments (0) | Permalink
Connecting to WCF Service from XNA on Windows Phone 7
1. January 2011 11:45

If you are using XNA Game Studio 4.0 to create an application targeted to Windows Phone 7, you may have tried to add a service reference to a WCF service inside visual studio and been stuck…

 

This appears to be a known issue – there is an easy workaround doing this manually with the Silverlight version of the SvcUtil application.

 

  1. Launch a command prompt
  2. Navigate to: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Tools
  3. Run SLSvcUtil /d:<output directory> <path to wsdl>
  4. Add the two created files (*.cs, and ServiceReferences.ClientConfig) to your existing XNA Project
  5. Select ServiceReferences.ClientConfig if the Solution explorer and change “Build Action” to “Content”

 

Here is an example of using the command:

C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Tools>slsvcutil /d:c:\mycode  http://test.com/test.svc?wsdl

 

Be sure to leverage the MSDN article for more information:

http://msdn.microsoft.com/en-us/library/cc197958%28v=vs.95%29.aspx

Tags: Comments (0) | Permalink
Remove Blocked File Types in SharePoint
9. January 2010 08:07

You can remove the blocked file types in SharePoint programmatically by accessing a collection on an SPWebApplication object.

Collection<string> be = webApplication.BlockedFileExtensions;
if (be.Contains("dll")) be.Remove("dll");
webApplication.Update();
Tags: Comments (0) | Permalink
Add Web Part to Page Programmatically
4. January 2010 09:32

I use the following code to programmatically add web parts to my pages.

I frequently see similar code, but no one is ever using the xml from the web part library to do the import, and as such the properties are not set to what was exported/defined in the web part xml.

Specifically:

XmlReader xmlReader = new XmlTextReader(webParts[0].File.OpenBinaryStream());

WebPart webPart = manager.ImportWebPart(xmlReader, out errorMessage);

 

 

Enjoy:

 

public static string AddWebPartToPage( SPWeb web, string pageUrl, string webPartName, string zoneID, int zoneIndex) { using (SPLimitedWebPartManager manager = web.GetLimitedWebPartManager( pageUrl, PersonalizationScope.Shared)) { using (System.Web.UI.WebControls.WebParts.WebPart webPart =

CreateWebPart(web, webPartName, manager)) { manager.AddWebPart(webPart, zoneID, zoneIndex); return webPart.ID; } } } public static WebPart CreateWebPart(SPWeb web, string webPartName, SPLimitedWebPartManager manager) { SPQuery query = new SPQuery(); query.Query = String.Format(CultureInfo.CurrentCulture, "<Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='File'>{0}</Value></Eq></Where>", webPartName); SPList webPartGallery = null; if (null == web.ParentWeb) { webPartGallery = web.GetCatalog( SPListTemplateType.WebPartCatalog); } else { webPartGallery = web.Site.RootWeb.GetCatalog( SPListTemplateType.WebPartCatalog); } SPListItemCollection webParts = webPartGallery.GetItems(query); XmlReader xmlReader = new XmlTextReader(webParts[0].File.OpenBinaryStream()); string errorMessage; WebPart webPart = manager.ImportWebPart(xmlReader, out errorMessage); return webPart; }

Tags: Comments (0) | Permalink