Karine Bosch’s Blog

On SharePoint

What if your sandbox solution contains a Visual WebPart?


As already mentioned in previous post, Microsoft decided to stop support for coded sandbox solutions on SharePoint Online. Developers will have to do the necessary effort to migrate the impacted sandbox solutions into solutions that comply with the recommended coding practices. You can find a lot of code samples and recommendations on the PnP site.

If your sandbox solutions contains a Visual WebPart, you will have to take action, because a Visual WebPart generates an assembly.In general, a Visual Web Part consists of the following:

  • an .ascx file with UI elements like HTML controls and ASP.NET controls
  • an .ascx.cs code behind file with some business logic that interacts with the UI and other data in the SharePoint site
  • a .webpart file that contains the definition of the web part (i.e. title of the web part, description, full name of the assembly, etc)

You could try to replace all ASP.NET controls by HTML controls, and develop the business logic in JavaScript and JSOM or REST. Now you don’t need that DLL anymore, right? Now you can get rid of the the assembly by setting the Include Assembly in Package project property to false in Visual Studio, right?

emptyassemby

Wrong! You can even try to remove the <%@Assembly> directives and the <%@Register> directives from the .ascx control:

visual webpart

Even if your Visual WebPart contains nothing else than HTML and JavaScript, that assembly is generated. This is because a Visual WebPart consists of an .ascx control. In SharePoint on premises environment, an .ascx control gets deployed to the /TEMPLATE/CONTROLTEMPLATES folder; but this is not the case with sandbox solutions. The .ascx control gets compiled into the DLL, meaning that all UI elements defined on the .ascx control are generated in code.

Trying to force things by removing the metadata element from the .webpart file, will result in an import error when the page loads:

webpart definition

In case of a complex Visual WebPart, your best option is to create a SharePoint Add-in Part:

  • A SharePoint hosted add-in consisting of HTML, JavaScript and using JSOM or REST to communicate with the host SharePoint site
  • A provider hosted add-in represented by an MVC application using CSOM to communicate with SharePoint

In case of less complex Visual WebPart, you could choose to replace it by embedding JavaScript

But all these approaches require you to go to each page that hosts the old Visual Web Part to replace it by the new development. This can be quite a challenge for large O365 tenants.

Another approach is to keep your .webpart file and change it to point to a JavaScript file. The advantage of this approach is that pages hosting your old Visual WebPart will now automatically host your new web part.

What are the steps you have to take to make this approach work?

  1. Write the JavaScript to replace the logic of your existing Visual Web Part
  2. Point the .webpart file to this JavaScript file
  3. Deactivate and remove the old sandbox solution
  4. Upload your JavaScript file into the Style Library of your site collection
  5. Upload the new .webpart file into the WebPart Gallery

Following image shows how you can modify the .webpart file:

  • Change the <metadata> tag to point to the ScriptEditorWebPart
    <metaData>
      <type name="Microsoft.SharePoint.WebPartPages.ScriptEditorWebPart, Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <importErrorMessage>Cannot import the migrated Demo Visual Web Part.</importErrorMessage>
    </metaData>
  • Add a <property> element with name Content
  • Add a reference to your JavaScript file
  • Add a <div> element that will be the container of the UI that you have to develop in the JavaScript file

webpart definition pointing to js

In your JavaScript you will have to retrieve this <div> element, to be able to embed the rest of the UI.

You can even automate steps 4 and 5. You can upload the JavaScript into the Style Library using the following CSOM code:

        private static void UploadFileToStyleLibrary(ClientContext ctx, string sourcePath, string styleLibFolder, string jsFileName)
        {
            // get the Style Library
            List styleLibrary = ctx.Site.RootWeb.GetList(ctx.Url + "/Style%20Library");
            ctx.Load(styleLibrary);
            ctx.ExecuteQuery();

            // upload the js file
            string fullSourcePath = sourcePath + jsFileName;
            if (!styleLibFolder.EndsWith("/")) { styleLibFolder += "/"; }
            string fullTargetPath = "/Style%20Library" + styleLibFolder + jsFileName;
            
            var fileCreationInfo = new FileCreationInformation
            {
                Content = System.IO.File.ReadAllBytes(fullSourcePath),
                Overwrite = true,
                Url = fullTargetPath
            };

            Microsoft.SharePoint.Client.File uploadFile = styleLibrary.RootFolder.Files.Add(fileCreationInfo);
            ctx.Load(uploadFile);
            ctx.ExecuteQuery();
        }

You can upload the new .webpart file into the WebPart Gallery using the following CSOM code:

        private static void UploadWebPartFile(ClientContext ctx, string sourcePath, string wepartFileName)
        {
            // get the WebPart Gallery
            List wpGallery = ctx.Site.RootWeb.GetCatalog((int)ListTemplateType.WebPartCatalog);
            ctx.Load(wpGallery);
            ctx.ExecuteQuery();

            // check if there is a file with the same name
            try
            {
                Microsoft.SharePoint.Client.File file = wpGallery.RootFolder.Files.GetByUrl(wepartFileName);
                ctx.Load(file);
                ctx.ExecuteQuery();

                // delete the file if it already exists
                file.DeleteObject();
                ctx.ExecuteQuery();
            }
            catch { }

            // updload the webpart file
            var fileCreationInfo = new FileCreationInformation
            {
                Content = System.IO.File.ReadAllBytes(sourcePath + wepartFileName),
                Overwrite = true,
                Url = wepartFileName
            };

            Microsoft.SharePoint.Client.File uploadFile = wpGallery.RootFolder.Files.Add(fileCreationInfo);
            ctx.Load(uploadFile);
            ctx.ExecuteQuery();
        }

If you prefer to work with a SharePoint Add-in to provision your files, you could follow the PnP approach for App Script Parts.

Good luck!

August 6, 2016 - Posted by | SharePoint 2010

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: