Dan Herzog, Author at Perficient Blogs https://blogs.perficient.com/author/dherzog/ Expert Digital Insights Fri, 02 Apr 2010 15:39:00 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Dan Herzog, Author at Perficient Blogs https://blogs.perficient.com/author/dherzog/ 32 32 30508587 Printer-Friendly SharePoint with IOTAP https://blogs.perficient.com/2010/04/02/printer-friendly-sharepoint-with-iotap/ https://blogs.perficient.com/2010/04/02/printer-friendly-sharepoint-with-iotap/#respond Fri, 02 Apr 2010 15:39:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=32

I’ve used methods in the past for creating printer-friendly versions of SharePoint pages, with varying degrees of success.But what I wanted was a simple, flexible solution that could easily be applied to existing sites.I found one here:http://www.iotap.com/Downloads/SharepointWebParts.aspx (scroll to the bottom).

Now this solution isn’t going to work for every situation you’ll encounter, but for several of my publishing sites it fit the bill nicely.Basically the solution as it comes will dynamically produce a new page consisting of the content inside the master page main placeholder – essentially the main content of your page, without the navigation, branding, etc. that can really clutter a printout.

It does this with a custom script that grabs a handle on a DIV, and then dynamically builds a new page based on its contents.A nice feature is that it also pops open your IE browser’s Print dialog.

If you’re a developer, one look at the code and you’ll likely come up with more ideas for taking this approach in other directions.On one publishing site, I only wanted a sub-section of the page to be printed, so I simply added a custom DIV to my Page Layout files and modified the script accordingly.

The solution comes with a web part that generates the print link, but you can also easily add the link to your master page directly, and completely control how and when it displays.

Thanks to the folks at IOTAP for coming up with a simple, clean approach to printing SharePoint pages.

]]>
https://blogs.perficient.com/2010/04/02/printer-friendly-sharepoint-with-iotap/feed/ 0 223650
Blocking SharePoint Designer https://blogs.perficient.com/2010/03/30/blocking-sharepoint-designer/ https://blogs.perficient.com/2010/03/30/blocking-sharepoint-designer/#respond Wed, 31 Mar 2010 03:00:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=31

Since the advent of free SharePoint Designer (SPD) downloads, many of us have wondered how to block users from using SPD on some SharePoint sites.While this may fly in the face of empowering your users, there are some (maybe a lot?) of sites that you just don’t want anyone to mess with.SPD can be a powerful tool, and in the wrong hands it can lead to way too many support tickets and site admin headaches.

If you’ve been lucky enough to get to try to resolve this, you’ve no doubt already read the guidance from the SPD Team at MS, and if you’re anything like me you found the solutions it presents less than perfect for your scenario.

Luckily there’s another solution available to SharePoint developers that’s making its way around the web, with a great example found on CodePlex by iwkid.Basically there’s a property that can be set in an SPWeb property bag, and that will block SPD from accessing your site.

The critical lines of code are:

spWeb.AllProperties.Add(“vti_disablewebdesignfeatures2”, “wdfopensite”);

spWeb.Update();

I’ll spare you all the implementation details – suffice it to say just get a handle on an SPWeb object, set the property, then update the SPWeb object.You can use what’s in the CodePlex solution or you can use this code sample to roll your own.You can create a utility exe to run thru your entire site collection, create an administration web part to turn SPD access on or off to a particular site (or a bunch of sites at once), or like in the CodePlex example create a Site Feature that can be turned on or off. Or anything else you can do in code – options are endless.

This solution was a life saver, and has worked out very nicely.We decided to implement it as a Site Feature – using the CodePlex solution as a starting point – allowing site admins to decide whether to grant or deny access.So far so good, we have not noticed any impact on any other functionality – InfoPath forms still work, which was the downfall of a previous solution we had tried.

Another thing I love about this solution – SPD gives a friendly little message to the user when they try to open a blocked site:

“The web site has been configured to disallow editing with SharePoint Designer.Contact your web site administrator for more information.”

Nice.

]]>
https://blogs.perficient.com/2010/03/30/blocking-sharepoint-designer/feed/ 0 223653
A Site Definition that Creates a Copy of Another Site https://blogs.perficient.com/2010/03/24/a-site-definition-that-creates-a-copy-of-another-site/ https://blogs.perficient.com/2010/03/24/a-site-definition-that-creates-a-copy-of-another-site/#respond Thu, 25 Mar 2010 04:05:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=30

I’ll describe a solution where we leveraged the SharePoint Content Migration API inside a Feature receiver to automatically generate exact copies of existing sites on demand.

We recently had a requirement to create multiple new site definitions, with the wrinkle thrown in that the users should be able to change a site definition on-demand without intervention from IT.The site definitions were to be used across dozens of site collections.

 

Ideally the users wanted to be able to configure a ‘template site’ somewhere in SharePoint, and have that site serve as the template for any site created with the given definition.The users could then update this template site, and any future sites based on that definition would essentially be copies of the template.

 

This presented a challenge, because it’s a bit different than how SharePoint normally works.Normally you decide what the site definition will include, and build your definition accordingly.The definition then lives in the 12 hive, and any changes require an update to the definition files.

 

Another option of course is to back the template site up as an STP template file, and make that available in the Site Template gallery.This is a good option to allow fairly easy site template updates (at least there’s no server file updates), but it just wouldn’t work well in this particular scenario:

  • In an STP, publishing pages tend to get customized (unghosted), we did not want this
  • An STP file has a low size limit
  • The end users would need to understand how to create a new STP, and then distribute the updated STP across the many site collections
    • If we would have gone with an STP-based solution, we would have built a utility to simplify this process.

 

SharePoint provides another way to create duplicates of existing sites, using the Backup & Restore functionality, creating a CMP file.CMP’s have advantages over STP’s in that there’s no customization of pages, a higher size limit, and most importantly we could automate the process to be totally seamless to the end users.

 

The basic solution consists of the following components:

  1. A site definition, defining a mostly blank site
    1. We can have multiple ‘configurations’ in a single site definition, useful for our multiple site
    2. Each configuration will display on the “Create New Site” page as a site template option
  1. A Feature
    1. Include this feature in each site definition configuration
    2. The Feature is empty, except that it calls a Feature receiver class
  1. A Feature receiver class – this is where the work is done
    1. This class will look for the template site, create a backup CMP of the template, and then restore that site on top of the newly created site.
    2. Leverages the Content Migration API in the SharePoint object model
  1. A site collection to house the template sites
    1. Along with some housekeeping bits

 

OK, so let’s review each component in a bit more detail….

The site definition’s ONET.xml file contains multipleconfiguration definitions, each looking essentially like the below.This example is for an “Accounting” site, and the custom Feature is in bold: (… is just some standard Features)

<Configuration ID=”0″ Name=”Accounting”>

<Lists />

<Modules>

<Module Name=”DefaultBlank” />

</Modules>

<SiteFeatures>

</SiteFeatures>

<WebFeatures>

<!– COPY SITE TEMPLATE FEATURE–>

<Feature ID=”A32F2EC8-D07A-4c6c-AC09-6FD91BA15555″>

<Properties xmlns=”http://schemas.microsoft.com/sharepoint/“>

<Property Key=”TemplateSiteName” Value=”Accounting”/>

</Properties>

</Feature>

</WebFeatures>

</Configuration>

Notice the “TemplateSiteName” property – the Feature receiver uses this value to determine which Template site to use as the source for the site being created.And don’t forget to create a new webtemp xml file to make these available!http://msdn.microsoft.com/en-us/library/ms447717.aspx

The Feature’s Feature.xml file is pretty simple.Notice we do set Hidden=”TRUE” to avoid having the Feature appear in the Feature gallery.

<?xml version=”1.0″ encoding=”utf-8″ ?>

<Feature Id=”A32F2EC8-D07A-4c6c-AC09-6FD91BA15555″

Title=”Source Site Copy”

Description=”This feature copies a source SPWeb into a new SPWeb.”

Version=”1.0.0.0″

Scope=”Web”

Hidden=”TRUE”

ReceiverAssembly=”PBCustomCode.FeatureReceivers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38e98″

ReceiverClass=”PBCustomCode.FeatureReceivers.SiteCopyReceiver”

xmlns=”http://schemas.microsoft.com/sharepoint/” >

</Feature>

 

The Feature receiver class is where the bulk of the work takes place.It’s custom code running in an assembly.For a good overview of how to create a Feature receiver, check here:http://www.nnihlen.com/blog/archive/2006/12/04/724.aspx

When a user chooses one of our custom site definition configurations, the class executes when the Feature is activated, which happens automatically during site creation.Here’s a breakdown of the

FeatureActivated method in our custom class:

  1. Find the Template site
    1. We have a custom SharePoint list at a known location in the Template site collection, with 2 colums:the Template Site Name and the URL of the template site.
    2. Doing a CAML query on this list, using the TemplateSiteName property value as a key, locate the URL of the template site.
      1. string sourceTemplateName = properties.Feature.Properties[“TemplateSiteName”].Value;
  1. Generate a CMP backup of the template site
    1. Find a good example of how to export to a CMP and then import it here: http://msdn.microsoft.com/en-us/library/aa981161.aspx
    2. You’ll want to save the CMP to a known location on the server.I name it with a GUID, and save it to a custom folder in the 12 hive.I also delete the file once I’m done with it.
  1. Import the CMP file right on top of the site we’re currently creating
    1. See the same example of how to export to a CMP and then import it here: http://msdn.microsoft.com/en-us/library/aa981161.aspx
    2. Import it directly into the URL of the new site.Add this line to the code, just after the line importSettings.SiteUrl = destinationSiteUrl; :

importSettings.WebUrl = web.ParentWeb.Url;

  1. A few important things to keep in mind:
    1. The SPWeb.Name value of the new site must be the same as the source site.It’s unlikely that your user happened to choose the same name as the template author, so we simply temporarily rename the new site with the same name.We’ll change it back later.
      1. To get a handle on the new site’s SPWeb object:

SPWeb newWeb = (SPWeb)properties.Feature.Parent;

  1. Both the Export and Import process should be run with SPSecurity.RunWithElevatedPriviliges
  2. Both the Template site and the destination site must have been created with the same site definition configuration
    1. So, keeping with our Accounting example, we need to create the Template site (in the Template Site Collection) by using the Accounting site template.
    2. When you create a Template site, you don’t want your Feature receiver class to execute.We avoid this by having the Feature receiver first check the URL of the current SPSite object.If it’s the same as the known Site Template Site Collection, we skip execution of any actual code.This allows the Template site to be created without any complications.
  1. Cleanup
    1. Delete the CMP file
    2. Rename the SPWeb.Name to the original value (as created by the end user)

 

OK, now you’re ready to try it out:

  1. In your site template site collection, create a new site using one of your custom site definitions
    1. Configure the site with lists, libraries, web parts, permissions, etc.
  1. Now, in a different site collection, create a new site using the same custom site definition
    1. The Feature receiver should activate.
    2. The code finds the URL of the template site, based on the TemplateSiteName property in the configuration definition.
    3. It will generate a CMP file at the location you specify.
    4. The code will temporarily rename your new site with the same name as the template site
    5. The CMP file will be imported right on top of your new site
    6. The code will rename your site to the original name, and delete the CMP file
  1. When the site creation process completes, you should have an exact duplicate of your template site.

 

I hope someone finds this approach useful, it has served us well so far.

]]>
https://blogs.perficient.com/2010/03/24/a-site-definition-that-creates-a-copy-of-another-site/feed/ 0 223659
Using a View as the basis for querying a List https://blogs.perficient.com/2009/12/30/using-a-view-as-the-basis-for-querying-a-list/ https://blogs.perficient.com/2009/12/30/using-a-view-as-the-basis-for-querying-a-list/#respond Thu, 31 Dec 2009 05:46:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=29
I recently had to create a custom web part that could consistently display list items in a consistent manner, and it had to allow the user to point it at any list with any filtering and sorting criteria. Rather than build my own filtering and sorting funcitonality, I found it easier, more user-friendly, and more flexible to leverage SharePoint’s list Views.
 
The idea is simple – let the users create a view, complete with sorting and filtering rules, and then use that as the basis for selecting the items to display. The SharePoint object model makes this easy.
 
The key is building an SPQuery object from an SPView object:

using (SPWeb rootWeb = SPContext.Current.Site.RootWeb)
{

//get list view
SPList theList = rootWeb.Lists[_listName];
SPView theView = theList.Views[_viewName];
//get the query, based on the view
SPQuery theQuery = new SPQuery(theView);
//run the query, get the items collection
SPListItemCollection viewItems = theList.GetItems(theQuery);
//build a display for the items in the collection

}
]]>
https://blogs.perficient.com/2009/12/30/using-a-view-as-the-basis-for-querying-a-list/feed/ 0 223678
Exporting SPD 2010 workflow to WSP https://blogs.perficient.com/2009/12/30/exporting-spd-2010-workflow-to-wsp/ https://blogs.perficient.com/2009/12/30/exporting-spd-2010-workflow-to-wsp/#respond Thu, 31 Dec 2009 05:12:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=28
SharePoint Designer 2010 makes it easy to create a workflow. What’s even better is that you can export that workflow, import it into Visual Studio 2010, and add code and custom activities.
 
You may find that exporting the workflow to a WSP in SharePoint designer fails. Luckily there’s a simple workaround once your workflow is deployed to a SharePoint 2010 site.
  • Go into that site and save it as a template (via Site Settings).
  • Then download the WSP from the site template gallery.
  • Now import the WSP into Visual Studio 2010, using the “Import Reusable Workflow” template.

I have found this workaround to work nicely.

]]>
https://blogs.perficient.com/2009/12/30/exporting-spd-2010-workflow-to-wsp/feed/ 0 223679
SharePoint 2010 https://blogs.perficient.com/2009/10/19/sharepoint-2010/ https://blogs.perficient.com/2009/10/19/sharepoint-2010/#respond Mon, 19 Oct 2009 20:08:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=27
SharePoint 2010 is official! The SharePoint Conference is underway in Vegas.
 
Pointbridge has posted quite a few SP2010 blog entries – see them here:
Office 2010 Wave Blogs
 
 
I contributed three so far myself:
  1. Quick Managed Metadata Overview
  2. Enforcing Relationships in Lookup Columns
  3. Column Validation in SharePoint 2010
]]>
https://blogs.perficient.com/2009/10/19/sharepoint-2010/feed/ 0 223520
Quick Managed Metadata Overview https://blogs.perficient.com/2009/10/15/quick-managed-metadata-overview/ https://blogs.perficient.com/2009/10/15/quick-managed-metadata-overview/#respond Thu, 15 Oct 2009 05:06:00 +0000 http://blogs.pointbridge.com/Blogs/2010wave/Pages/Post.aspx?_ID=31

Managed Metadata is an interesting and powerful new feature of SharePoint 2010. This is a very high-level overview of the feature. I’d suggest following along in your own SharePoint 2010 environment.

  1. The Termset

A Managed Metadata Termset is a hierarchy of terms that are managed at a central location and that can be made available for use as metadata on SharePoint entities, like list items.

Termset 1

Here’s how it looks when using managed metadata in a list column. In this screenshot, we’re adding a new item to a list, and populating the MM1 column with a term from our Termset:

Termset 2

  1. Managed Metadata at the Site Collection level

A site owner or content administrator can easily create and manage a Termset at the site collection level. The Termset can be used throughout the site collection.

Let’s look at one way to do this:

    1. Create a column (can create a site column or a list column)
    2. Choose field type "Managed Metadata"
    3. Select "Customize your termset"
    4. Create a Termset hierarchy

Termset3

  1. Managed Metadata at the Enterprise level

Another way to create Managed Metadata Termsets is at the Enterprise level. To do this, we take advantage of the new Service Application model in SharePoint 2010. A full discussion of Service Applications is outside the scope of this posting, but in a nutshell think of them as services that can be consumed by any application in any farm that can access them. We can create a Managed Metadata Service Application, and then create Termsets in this Service App that can be used in any site across the enterprise.

Let’s look at how we can set this up:

    1. Ensure the Managed Metadata Web Service is running
      1. Open Central Administration
      2. Go to "System Settings"
      3. Click "Manage Services on Server"
      4. Ensure the Managed Metadata Web Service is started

MM Service

    1. Create new Managed Metadata Service Application
      1. Open Central Administration
      2. Go to "Application Management"
      3. Click on "Manage Service Application"
      4. Click "New" in the Ribbon
        1. Select "Managed Metadata Application"

MM Service 2

5. Fill in the form to create the Service Application

MM Service 3

    1. Click on the newly created Managed Metadata Service
    2. Assign a Term Store Administrator and Create a termset hierarchy

MM Service 4

e. This Managed Metadata Termset can now be used to create a Managed Metadata column in any list across the enterprise.

  1. A few things a site manager can do with Managed Metadata:
    1. Easily tag items with metadata that is highly organized, and consistent throughout the site.
    2. Centrally manage the terms in a Termset that are used across the site collection, or the enterprise.
    3. Enable metadata navigation

  1. A few things a user can do with Managed Metadata
    1. Tag content using the new social collaboration features in SharePoint 2010
    2. Filter content using metadata navigation
    3. Search for content using standardized metadata terms
]]>
https://blogs.perficient.com/2009/10/15/quick-managed-metadata-overview/feed/ 0 223534
Enforcing Relationships in Lookup Columns https://blogs.perficient.com/2009/09/26/enforcing-relationships-in-lookup-columns/ https://blogs.perficient.com/2009/09/26/enforcing-relationships-in-lookup-columns/#respond Sat, 26 Sep 2009 15:09:00 +0000 http://blogs.pointbridge.com/Blogs/2010wave/Pages/Post.aspx?_ID=12
In SharePoint 2010 we can now have a greater level of control over the realtionship between a lookup column and the items in it’s source list.
When you create a lookup column, you’ll see the option to create a relationship:
These relationship enforcements are a powerful way to ensure that your list item metadata maintains its referential integrety.
One interesting thing is the behavoir of the Recycle Bin when you have Cascade Delete set on a column. If you delete a source item, it will of course delete other items that refer to that item. If you look in the Recycle Bin, you’ll only see one item – the item from the source list.
Notice the relationship icon next to the item – this lets you know that this item represents an enforced relationship. If you restore this item, it will also restore the related items that it deleted.
A few other things to keep in mind about relationship enforcement:
1. It is not available if you allow Multiple Values on the lookup column.
2. It is not available in Site Columns
3. When you set a relationship, the column will automatically be indexed.
]]>
https://blogs.perficient.com/2009/09/26/enforcing-relationships-in-lookup-columns/feed/ 0 223560
Column Validation in SharePoint 2010 https://blogs.perficient.com/2009/09/10/column-validation-in-sharepoint-2010/ https://blogs.perficient.com/2009/09/10/column-validation-in-sharepoint-2010/#respond Thu, 10 Sep 2009 06:41:00 +0000 http://blogs.pointbridge.com/Blogs/2010wave/Pages/Post.aspx?_ID=5

The ability to easily validate the column values entered into list items is a welcome addition to SharePoint 2010. I’d like to walk thru 2 simple example s of how to use column validation, at the column level, then at the list level. I’ll then point out some specific notes about this feature.

Simple Example #1 – Column Level

  1. Create a new column on a list, and click "Column Validation":

  1. Add a validation Formula, and a message that will display if validation fails:

  1. Create a new item, and enter a value that will not validate. Click OK. You will see your failure message:

Simple Example #2 – List Level

  1. In the List Settings, click on "Validation Settings"

  1. Enter a validation formula to apply to this list. Click Save.

  1. Create a new list item, entering in values that will not validate. Click OK. The item does not save, but the User Message doesn’t appear either. I assume this is a bug, and it ought to be fixed before RTM.

Field Types

In this simple example we used a "Single Line of Text" field type. The following field types can be validated with the "Column Validation" feature:

  • Single Line of Text
  • Choice (single only)
  • Number
  • Currency
  • Date & Time

Formulas

  1. You can only compare column values to one another in a list level validation.
  2. A validation formula at the column level cannot include any other columns besides itself. For example, [Column1]>[Column2] is an invalid formula and SharePoint will not allow it to be used at the column level. In this case, you want to use list-level validation.
  3. There is only one formula available at the list level.
  4. The formula syntax is similar to that used in Calculated Columns

There are a few dozen functions available – I have not tried every one. One interesting thing to note is that SharePoint 2010 would not allow me to use the TODAY function, even when validating a Date field. [DateColumn]>TODAY is not a valid validation formula.

Conflicts

  1. What if you have both column level validation and list level validation?
    1. The column level formulas will be evaluated first, then the list formulas
  1. What if the column and list level validations are in conflict?
    1. Example – at the list level, you require that [Text1] = [Text2], but each column has it’s own validation; [Text1]="AAA", and [Text2]="BBB". In this case, it will be impossible to actually submit a list item. The column validations are evaluated first, but if the values validate here, they will of course fail the list validation.
  1. What if the list level validation includes columns not included in a particular content type?
    1. If a column used in the list formula isn’t available in the current content type, validation will always fail. This means that if you have multiple content types in your list, you should not validate at the list level for a column that is not included in all content types on the list. These columns can only be validated at the column level.

Site Columns

  1. You can set validation on custom columns of the field types listed above
  2. You can override the validation of a site column at the list level

Items To Investigate

  1. How does validation behave with page fields in a Pages library on a publishing site?
  2. How does validation behave in Office client applications?
  3. Is validation available in the Site Directory? Does it work at site creation time?
  4. Can we use regular expressions in a validation formula?
]]>
https://blogs.perficient.com/2009/09/10/column-validation-in-sharepoint-2010/feed/ 0 223566
“List does not exist” error in SharePoint https://blogs.perficient.com/2009/03/24/list-does-not-exist-error-in-sharepoint/ https://blogs.perficient.com/2009/03/24/list-does-not-exist-error-in-sharepoint/#respond Wed, 25 Mar 2009 01:51:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=25

We had a page with a few custom web parts on it, and some users would get this error message while others did not. Obviously since some users didn’t get the error, the lists must all at least exist, so I first assumed it was probably a permissions thing on one of the lists being accessed by one of the custom web parts.

After an exhaustive check of permissions on every list in the site, I was able to rule that idea out. The message "List does not exist" didn’t seem to be exactly helpful.

With some trial-and-error I was able to narrow it down to one web part, so I opened the code and started walking thru it. I finally found the culprit… in one section of the code I found something like this:

SPUserCollection groupUsers = theGroup.Users;

So you see the code is trying to get a list of all the users that belong to a particular Group. In this case, different users would get different values for theGroup, and it would not always be a group they belonged to. Here’s where it would break.

If the current user didn’t belong to the Group, the Group would need to allow Everyone to see it’s members, which is luckily a property of a SharePoint Group – just go to the Group and select "Group Settings" from the "Settings" dropdown:

Group settings

Once that was set to "Everyone" on the Groups, the problem went away. Of course, another (possibly better) way to fix this would be to run the code under elevated permissions. But at least I got to the bottom of the error.

And the lists did exist 🙂

]]>
https://blogs.perficient.com/2009/03/24/list-does-not-exist-error-in-sharepoint/feed/ 0 223460
Secure and Nonsecure in SharePoint https://blogs.perficient.com/2009/03/23/secure-and-nonsecure-in-sharepoint/ https://blogs.perficient.com/2009/03/23/secure-and-nonsecure-in-sharepoint/#respond Tue, 24 Mar 2009 02:10:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=24

This page contains both secure and nonsecure items

nonsecure message

Since you may be running SharePoint in a secure (HTTPS) environment, such as for a corporate intranet, you may encounter this popup warning message from time to time. Of course, it’s not actually an error message, but users will find it annoying and may regard it as an error.

More often than not it’s something simple, like an image pulled in from an external nonsecure site, or an iframe pulling in a nonsecure site. Sometimes though, it’s just plain weird and tough to uncover. Here are a few i’ve run into…

  1. The Menu control

On one page we had a custom web part, and the web part happened to use a Menu control. It contained one visible node, and when a user hovers over the node a flyout appears with the subnodes. We found that in IE6 browsers, when the user would hover over the visible node in the Menu control, the "secure and nonsecure" warning popup would appear. It didn’t seem to matter whether the user would select "Yes" or "No", the control would end up working fine.

This was maddening to resolve, but I eventually ran into the explanation from Jerry Ormon at MS. It seems that the Menu control uses a hidden iframe, which points to "about:blank", which IE6 sees as nonsecure. http://support.microsoft.com/kb/910444 Thankfully, it’s pretty simple to resolve – just register a startup script that overrides the iframe URL with the blank.htm file that lives in the _layouts directory.

Add something like this code to your web part’s Render override:

string ie6fixJS = menuControl.ClientID + "_Data.iframeUrl=’/_layouts/blank.htm’;";

Page.ClientScript.RegisterStartupScript(typeof(this), "MenuHttpsWorkaround_jll", ie6fixJS, true);

Note that we did not see this behavior with IE7, only IE6.

  1. Redirect in dropdown OnSelect event

Again, with IE6 only. We didn’t see this problem in IE7.

We have a page that has a dropdown list, allowing the user to select a project name. When a selection is made in the dropdown, the server-side event handler redirects the user to the proper SharePoint Publishing subsite. Of course, since it’s a SharePoint Publishing site, we’re not redirecting directly to a page, but to the site’s URL, such as https://moss/subsite1. As you know from experience, when you hit the site’s URL, SharePoint will redirect you to the welcome page of that site, perhaps https://moss/subsite1/Pages/home.aspx. This is where it gets nasty.

SharePoint handles that welcome page redirect by issuing 301 responses, which essentially tells your browser to make another request to the full welcome page URL. When the redirect happens in the course of an OnSelect event from a dropdown list, you’ll find that one of the 301’s issued by the server is nonsecure (HTTP instead of HTTPS). Yuck. You have a couple of options at this point.

First, you can change your redirect code to go to the full welcome page URL. You can do this pretty easily by getting an PublishingWeb object of the site you’re redirecting to, then inspecting that object’s DefaultPage property.

Another option is to not do a server-side Response.Redirect at all, but use the old HTML META Refresh method:

Response.AppendHeader("Refresh", "0; URL=" + url);

This will cause the page to post back, then add a tag to the response page that will instruct the browser to redirect to the URL in the tag. Problem solved.

  1. RSS Feeds

This one can be a problem in IE6 or IE7.

Your users may find the RSS Viewer web part to be very useful – and it is for the most part. But when you’re in an HTTPS secure environment, and a user points the RSS Viewer at some external feed, the data returned by that feed may contain embedded HTTP resources, such as an image tag with it’s source pulling in from a nonsecure site:

<IMG SRC="http://www.somesite.com/demo.jpg" />

Here’s a fairly simple quick’n’dirty workaround… create a new page in the _layouts directory, called something like rssFilter.aspx. The page will get the RSS feed and then parse out wherever it sees a SRC property with a non-secure value. It then re-serves the updated feed. Now, train the users to point the RSS Viewer to:

/_layouts/rssFilter.aspx?rssUrl=<rss url>

I’m sure there are other solutions to the above problems, but these worked nicely for us.

]]>
https://blogs.perficient.com/2009/03/23/secure-and-nonsecure-in-sharepoint/feed/ 0 223465
Mass Checkin of SharePoint Files that were Never Checked In https://blogs.perficient.com/2009/02/18/mass-checkin-of-sharepoint-files-that-were-never-checked-in/ https://blogs.perficient.com/2009/02/18/mass-checkin-of-sharepoint-files-that-were-never-checked-in/#comments Thu, 19 Feb 2009 02:55:00 +0000 http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=23

A few days ago we ran into a situation where a user had uploaded dozens of documents into dozens of libraries on dozens of sites. The problem was that the user had uploaded multiple documents at a time into libraries that had multiple content types, so none of these documents were checked in. Since they had NEVER been checked in, the documents were only visible to the user who had uploaded them.

SharePoint offers a handy feature (Site Actions > View Reports > Checked Out To Me) where that user can see the documents checked out to them, and even check them in all at once. This is great, but in our situation since permission inheritance was broken on each of the subsites, there was no way to view all the documents across all the sites, just on one site at a time.

So, here we are faced with the daunting task of manually going thru dozens of sites looking for documents to check in. As a developer, your first instinct is to turn to a programmatic solution to avoid this huge manual process.

We needed a simple utility to look for items that had never been checked in across all sites in the collection, and check them in. Just a little console .exe…

First get a handle on the SPSite object:

using (SPSite mySite = new SPSite(siteCollectionURL))

Now you need to impersonate the user who uploaded the documents. Only that user can see those documents. A site collection admin can’t. The app pool account can’t. Only the original uploader.

SPUser impersonateUser = mySite.OpenWeb().AllUsers[@"DOMAINuser.name"];
SPUserToken token = impersonateUser.UserToken;

Now get a new SPSite object. All objects you create from the SPSite will run under the impersonated account.

mySite2 = new SPSite(siteCollectionURL, token);

Then loop thru the SPWeb’s:

foreach (SPWeb myWeb in mySite2.AllWebs)

Look for SPFolder’s:

foreach (SPFolder myFolder in myWeb.Folders)

Check each SPFile to see if it’s checked out:

foreach (SPFile myFile in myFolder.Files)
{
if (myFile.CheckOutStatus != SPFile.SPCheckOutStatus.None)

And check it in:

myFile.CheckIn("Checked in by utility.");

If you have publishing set on the document library, you may want to publish it too:

myFile.Publish("Published by utility.");

The only piece of this that surprised me (but probably shouldn’t have) was the need to impersonate the original uploader.

I should also note a few caveats:

  1. The above code will check in all files checked out to the impersonated user – not just the ones that have never been checked in. If you want, you can inspect the Versions collection on the SPFile object to see the history.
  2. The above code will also check in pages in the Pages library if you have a publishing site. You can add a conditional to skip over the Pages library in your loop if you want.
  3. I found that to work properly, my impersonated user had to be a Site Collection Admin.

]]>
https://blogs.perficient.com/2009/02/18/mass-checkin-of-sharepoint-files-that-were-never-checked-in/feed/ 1 223306