I feel this particular issue really deserves a blog post due to the sheer number of bad answers that are out there that don’t really address or explain the underlying issue.
Scenario: Let’s say you have an asp:DropDownList control that you populate with three values in your Page_Load event:
<asp:DropDownList ID="rcbStatus" ToolTip="Status" runat="server" Width="200px"> <asp:ListItem Value="1" Text="A"></asp:ListItem> <asp:ListItem Value="2" Text="B"></asp:ListItem> <asp:ListItem Value="3" Text="C"></asp:ListItem> </asp:DropDownList>
which renders as:
<select>
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>Now let’s say you want to manipulate the above using client side javascript and perhaps alter/append or remove options from the above select based on some other selection. So we end up with a select control that looks like:
$("#<%= rcbStatus.ClientID %>").append($('<option></option>').val('4').html('D'));
<select>
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
<option value="4">D</option>
</select>Now go ahead and select option “D” and attempt a submit, you will receive an error as follows (if EnableEventValidation is true, which is the default):
Invalid postback or callback argument. Event validation is enabled using
in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.
Now sites like stackoverflow and several other blogs outline the following as potential fixes for this error:
- Set EnableEventValidation to false and of course the above submit will work. The reasoning is that you shouldn’t be relying on EventValidation to ensure that input from the user/page is what you expect and is valid input.
- Use an AJAX Update Panel or a Telerik RadUpdatePanel to handle the change client side.
- Use a select control natively, instead of an asp:DropDownList and use Request.Form to access it’s selected value on submit.
- Or finally, do what the error is suggesting and register the possible range of values using ClientScript.RegisterForEventValidation.
I’m going to demonstrate the last option there, as it’s the one that makes the most sense for my particular scenario. Add an override for the Render method in your server side code as follows:
protected override void Render(HtmlTextWriter writer) { Page.ClientScript.RegisterForEventValidation(rcbStatus.UniqueID, "4"); base.Render(writer); }
Now for option D in my select, with a value of 4, the EventValidation is aware that 4 is a valid and expected result and the submit will occur without issue. So basically, we’re telling ASP.NET what is valid and to continue on if you encounter these entries that did not exist in the original state of the drop down list when it was rendered.
Please note that specifying “D” as the second parameter in the RegisterForEventValidation method did not work for me, it had to be the option value.
Hi all, I was compiling a list for everyone here at Black Ninja that outlines some upcoming free SharePoint events to attend, and thought it may be worthwhile to post to my readers:
- VanSPUG (http://www.vanspug.com/default.aspx) – Joel Oleson and Christian Buckley are talking Migration and Failed Deployments
- SharePoint Saturday Online (http://www.sharepointsaturday.org/emea/Pages/meetings.aspx) – Really great SharePoint Online Conference run by some pretty solid community leaders
- SharePoint FireStarter (https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032473308&Culture=en-US) – This is being hosted in Redmond as an in person or online event for SharePoint Developers
- DevExpress (http://www.devexpress.com/Support/Webinars/) – DevExpress and Andrew Connell are hosing a couple webinars on SharePoint Dev and External Data
All of these events look awesome and I’ll be attending them all!
I’ve got a backlog of articles that are in draft mode, waiting to be proof read and published, but this particular topic I wanted to take a minute and write about.
There is a whole slew of information out there for the best ways to create a Cloneable SharePoint 2007 Environment. Why might you want to do that? Well for our particular case, we do a lot of training here at Black Ninja, so depending on how many students we register, we like to provide each with their own isolated SharePoint 2007 environment.
In the past, we’ve done this a bit too manually for my liking. So this time around, I took some time and looked into our options for creating cloneable vm’s easily and without hassle. My starting point was Michael Sivers awesome blog post titled: “How to Create a Cloneable SharePoint Development Environment“. I followed his instructions to a point, and because I’m running a VMWare fusion environment, I had to tweak things a little bit. I also wanted to exclude the auto farm creation and deployment because I wanted to do those steps myself.
Software – Below is a list of software I used for my training VMs:
1. VMWare fusion for the mac, installed on my Mac Pro server that we use to host our VMs. This machine has 16GB of ram (soon to be 32GB) and an 8-core process.
2. Microsoft Windows Server 2003 Enterprise R2 with SP2
3. Microsoft SQL Server 2005 Developer Edition
4. Microsoft SharePoint Server 2007
5. Microsoft Visual Studio 2008 Professional
6. Visual Studio Extensions for WSS 1.3
7. Office Server SDK
8. SharePoint Designer 2007 with SP1
9. Firefox, Firebug and Web Developer extensions
10. Office 2007 Ultimate
11. Sysprep for Win2K3 SP2
Base Image – Below is a list of steps for creating the base image:
I used all of Michael’s steps except right before the Install Sysprep for Win2K3 SP2 step, I did the following:
1. Install SharePoint Designer 2007 with SP1
2. Install Firefox, Firebug and the Web Developer extensions
3. Install Office 2007 Ultimate
4. Run Windows Update
5. resume with Michael’s step: Install Sysprep for Win2k3 SP2
So what we’ve essentially just created is the base machine for all the other clone’s we’re going to create. The first step is to shut down this new VM and make a copy/backup of it. The reason we do this is because future training classes may require additional software, or patches and so you would spin up the backup, make the updates/installations and rerun Sysprep to create a new cloneable base.
So, Michael includes 3 files for your use that need to be configured before we run Sysprep: Sysprep.inf, startsql.bat and mossconfig.bat. In my case, I commented out the reference to mossconfig.bat in the Sysprep.inf file. I also made the changes to the startsql.bat file so that it uses the built in Administrator account.
Because I hadn’t used Sysprep in so long, I had no clue how to use it. In the end, I was able to find it in the deploy.cab file located in c:\Windows\system32.
I extracted the contents of the deploy.cab file to c:\sysprep. I copied my modified Sysprep.inf and startsql.bat files to that location. From the command line, I navigated to c:\sysprep and ran the following command:
sysprep -mini -quiet -reseal shutdown
Once my machine is shut down. I am ready to roll. Michael talks about Differencing .VHD files, but research seemed to indicate the VMWare Fusion equivalent was to simply copy the VM. So basically, to make clone’s of these VMs I simply copy and paste to make a copy. I rename the VM, start it up and walk through the prompts to configure the new server. Once that boots, I created a local user account: moss_farmsvc and ran the SharePoint Configuration Wizard. When prompted, I have it the moss_farmsvc account, specified the db server, and configured CA to run on port 8888. Voila, I’ve got one VM ready to go. Rinse and repeat until you’ve got enough VMs for all your students!
Because I don’t write nearly enough on this topic, I figured why not add another post about the splendid PeopleEditor control for SharePoint. Actually, these posts happen to be among my most popular. So popular in fact, that they are constantly being stolen and posted on other blogs without so much as a courtesy ping back! I won’t point any of those users out as they don’t deserve any precious link love. However, if you come across a PeopleEditor post that looks suspiciously like mine, I’m the original author!
Ok, so now that my rant is over, let’s go over a new trick I recently discovered when working with the PeopleEditor. Whenever I’ve worked with this control in the past, I’ve usually only dealt with SelectionSets that are limited to Users. So there has never been a need to handle entries where groups are specified. In case you are not familiar, here is a listing of the possible options for the SelectionSet property, posted by Alex and Ozaki on the MSDN PeopleEditor.SelectionSet Page – Community Section:
- User = single user
- DL = AD distribution list
- SecGroup = AD security group
- SPGroup = SharePoint group
I came across this requirement recently. More specifically, I needed to be able to save both users and groups, but obviously the logic for saving those is a little different. So we need a mechanism that helps us determine what type of entity a user has provided and based on that, process the correct save method.
So, let’s say we have a PeopleEditor defined as follows:
<SharePoint:PeopleEditor ID="peManager" runat="server" MultiSelect="false" Width="200px" AllowEmpty="true" SelectionSet="User,SPGroup" />
Now we want to save whatever the user enters into a column of type Person or Group that can accept both users and groups.
foreach (PickerEntity entity in peManager.ResolvedEntities) { switch ((string)entity.EntityData["PrincipalType"]) { case "User": item["Assigned"] = SavePeopleEditorControl(peManager.CommaSeparatedAccounts); break; case "SharePointGroup": SPGroup group = web.Groups[entity.EntityData["AccountName"].ToString()]; item["Assigned"] = group; break; // add additional case statements for the other SelectionSets } }
There you have it. Enjoy!
I struggled with the title of this post, because there are several different uses for the Event Receiver I’m going to talk about. In SharePoint 2007, it was common to use a Feature Receiver that was stapled to a Site/Site Definition for performing additional tasks after a Web was provisioned. We leveraged a Feature Receiver, because there didn’t exist an Event Receiver that handled the “Web Added” event. This is where the Web Provisioned event comes into play for SharePoint 2010 development. And a huge thanks to whoever was on the MS team that made that happen.
So let me setup a scenario I was working on recently and discuss the options for how that might be achieved.
Requirement: There exists a team site called Projects. Any sub sites created under Projects need to automatically inherit it’s parent site theme and navigation. We can get a little more complicated by doing things like adding web parts to the default.aspx page automatically or automatically adding an entry to the parent quick launch bar that includes a link to newly provisioned sites, but I’ll cover that in another post.
- Within Visual Studio, you want to create a new Project. On the left, expand the SharePoint heading and select Event Receiver on the right. Click OK to create the new project.
- The next screen will ask for the debugging url and whether or not you want this to be a sandboxed solution. Fill those in as required.
- The next screen is where we get to define what type of receiver we’re looking for. In this case, we’re going to use one of the NEW SharePoint 2010 receivers. In the drop down asking What type of event receiver we want, select Web Events. Now check the box next to A site was provisioned. Click Finish.
- Visual Studio will take care of all the setup for the Event Receiver, and once loaded, it should default you to the EventReceiver1.cs file.
- Now let’s add the code that will be responsible for changing the navigation of the new site to inherit from it’s parent. And let’s also make the change so the sub site is themed like the parent.
- Go ahead and build the solution. Right click on the project in the Solution Explorer and click Deploy.
- Once the solution is deployed, open up your browser and navigate to your site url. Notice from the screenshot below, I have a Projects site with the Azure theme applied.
- An important piece to understand is that the Web Provisioned event needs to be activated at the Projects level, because we want the code we wrote to run on any sub sites created under Projects. So go ahead and navigate to Site Actions, Site Settings, Manage site features and activate our new feature.
- Go ahead and create a new sub site. You might notice that it appears as though nothing happened. For example, why does it appear as though the theme was not set? Well, if you hit refresh, you’ll see that the theme was in fact set. There is a property in the Event Receiver’s Elements.xml file that will fix this, so it doesn’t require a refresh. Take a look at the before and after for the xml listed below. I’ve added a line that sets the Synchronization property. The default is asynchronous, however, we want it set to synchronous. Asynchronous means that events typically run at the same time, so the custom code is run, but instead of waiting for it to finish, the page loads and we might not have finished setting it’s properties yet. By specifying that we run it synchronously, it will wait for the code to complete before attempting to load the page.
- Re-Deploy the solution and create another sub site. Test that it properly sets the values when the page loads. If it doesn’t work immediately, deactivate and reactivate the feature. I find I often have to do that after deploying a new version of a solution.
public class EventReceiver1 : SPWebEventReceiver { /// /// A site was provisioned. /// public override void WebProvisioned(SPWebEventProperties properties) { base.WebProvisioned(properties); } }
public override void WebProvisioned(SPWebEventProperties properties) { base.WebProvisioned(properties); SPWeb web = properties.Web; // set navigation to parent nav web.Navigation.UseShared = true; // set theme to parent theme ThmxTheme.SetThemeUrlForWeb(web, ThmxTheme.GetThemeUrlForWeb(web.ParentWeb)); web.Update(); }
Before
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers > <Receiver> <Name>EventReceiver1WebProvisioned</Name> <Type>WebProvisioned</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>WebAddedEvent.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> </Receivers> </Elements>
After
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers > <Receiver> <Name>EventReceiver1WebProvisioned</Name> <Type>WebProvisioned</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>WebAddedEvent.EventReceiver1.EventReceiver1</Class> <SequenceNumber>10000</SequenceNumber> <Synchronization>Synchronous</Synchronization> </Receiver> </Receivers> </Elements>
That’s it folks, a really simple overview of the new Web Provisioned event receiver. Please post a comment if anything is unclear.
I had such a hard time getting this to work, it most definitely deserved a blog post. Hopefully others can make sense of this by reading this post.
Scenario
I wanted to do some conditional formatting on my rows of data using the gridComplete method. In order for me to do conditional formatting, I need to be able to access any column for a given row, so I can affect the cell contents. Now, from a jqGrid wiki/documentation perspective, there appears to be two different methods we could use: setCell or setRowData.
setRowData is what we’re going to talk about here. Consider the following code:
gridComplete: function() { var rowData = $("#backlog").getRowData(); for (var i = 0; i < rowData.length; i++) { $("#backlog").jqGrid('setRowData', rowData[i], false, {color:'red'}); } },
Now before we get into what this does specifically, the above won’t work, and you won’t have a clue why. No error messages, nothing in the Firefox console, nada. I really scratched my head over this for a while, until I started to notice that users on forums and stackoverflow were using getDataIDs, not getRowData. So re-written as follows, it works:
gridComplete: function() { var rowData = $("#backlog").getDataIDs(); for (var i = 0; i < rowData.length; i++) { $("#backlog").jqGrid('setRowData', rowData[i], false, {color:'red'}); } },
So while the above does work, it’s important to understand why the previous bit of code did not. If you want to use getRowData, then when a method like setRowData asks for rowID, instead of passing in rowData[i], you need to specify rowData[i].ID. That’s the key differentiator. If we use getDataIDs, obviously we can use rowData[i] because the array only contains IDs, instead of the entire row object.
Now, what does the above do. Well, it iterates through all the rows for your grid, and set’s the color of each cell text to red.
One other thing to note, if you want to set a different style like background-color, you won’t be able to set it by simply replacing color with background-color, you’ll need to set a class and define your background-color in your class:
.myclass td { font-weight : bold !important; background-color: red !important; color: white !important; } ... gridComplete: function() { var rowData = $("#backlog").getDataIDs(); for (var i = 0; i < rowData.length; i++) { $("#backlog").jqGrid('setRowData', rowData[i], false, 'myclass'); } },
It’s important to note that the false parameter simply means that I want to affect the entire row, if you wanted to single out a particular column FOR ALL ROWS, it would look like this:
gridComplete: function() { var rowData = $("#backlog").getDataIDs(); for (var i = 0; i < rowData.length; i++) { $("#backlog").jqGrid('setRowData', rowData[i], {Title:'some new content for cell'}, 'myClass'); } },
Hopefully that was helpful!
Shereen
I’ve been working pretty heavily the last couple weeks with List Definitions, List Instances and Site Definitions in SharePoint 2010. I’m documenting my process because I was hard pressed to find a solid example of this on the web. I’m mostly concerned with documenting the areas that I found difficult, like the View definition in the Schema.xml and the changes to the Onet.xml Modules element in 2010. What I won’t cover is how to use Visual Studio 2010 to create a new Site Definition project, and add List Definitions to it. Perhaps in another post I’ll try to outline the whole process in more detail.
Let me setup the scenario:
1. I am using Visual Studio 2010 to build a Site Definition that will contain a List Definition and an instance of that List.
2. I want the instance of the List that I create to show up on the default.aspx page of my site automatically when I provision a site using this definition.
3. Finally, I want to display a full toolbar so users can add items directly from the default.aspx page.
Schema.xml
<View BaseViewID="50" Type="HTML" MobileView="TRUE" MobileDefaultView="TRUE" ImageUrl="/_layouts/images/generic.png" WebPartZoneID="Main" WebPartOrder="1" Url="Forms/Last Modified.aspx" SetupPath="pages\viewpage.aspx"> <Toolbar Type="None" /> <XslLink>main.xsl</XslLink> <Query> <OrderBy> <FieldRef Name="Modified" Ascending="False"/> </OrderBy> </Query> <ViewFields> <FieldRef Name="DocIcon"></FieldRef> <FieldRef Name="LinkFilename"></FieldRef> <FieldRef Name="_UIVersionString"></FieldRef> <FieldRef Name="Editor"></FieldRef> <FieldRef Name="Status"></FieldRef> <FieldRef Name="Category"></FieldRef> </ViewFields> <RowLimit Paged="FALSE">5</RowLimit> <Aggregations Value="Off" /> </View>
So some things to note in the above.
- The Toolbar Type attribute caused a bit of confusion for me because the schema complains that it’s invalid if I set it to a value of None. It works for me anyway. There is a ton of information on the web that describes what these values are allowed to be. I find the following article from MS documents the options well:
- Standard —The most common type of toolbar, which is used, for example, in the All Items views for most lists, and which corresponds to Full Toolbar in the Web Part tool pane.
- FreeForm —Used in Default.aspx and Web Part Pages and corresponds to Summary Toolbar in the Web Part tool pane.
- None —No toolbar is used in the view, corresponding to No Toolbar in the Web Part tool pane.
-
When adding
elements to this xml file, ensure that the Name you specify is the Internal name of that field, not the display name. For things like Version, I was assuming the internal name was Version when it fact it was _UIVersionString or _UIVersion. I haven’t found a neat way to discover these internal names for system or hidden fields, but if I do, I’ll update this post. - Make sure you add a SetupPath tag that points to “pages\viewpage.aspx” so it knows where to go to generate your view.
- Finally, be really careful not to set the DefaultView property on more than one View element. I find by doing that, it creates a completely separate list, instead of a view within the current list.
Onet.xml
Ok so when we’re ready to add our List Definition to the Onet.xml, a few things slowed me down that I want to point out here. I’m going to show two ways that you would add a list/view to the default.aspx page:
<View List="Project Documents" BaseViewID="1" WebPartZoneID="Right" WebPartOrder="1" />The above code references a List Definition I have already created called Project Documents, I’m looking for the BaseViewID of 1 (this should be defined in the Schema.xml) and I’m specifying where to position my web part. This technique works really well for me, except, I am not able to set things like the Title of the web part or it’s Chrome.
So I could have done the following:
<View List="Project Documents" Name="Last Modified Project Documents" DisplayName="Last Modified Project Documents" BaseViewID="50" WebPartZoneID="Right" WebPartOrder="2"> <![CDATA[ <webParts> <webPart xmlns="http://schemas.microsoft.com/WebPart/v3"> <metaData> <type name="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart,Microsoft.SharePoint,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" /> <importErrorMessage>Cannot import this Web Part.</importErrorMessage> </metaData> <data> <properties> <property name="Title">Last Modified Project Documents</property> <property name="AllowConnect" type="bool">True</property> <property name="AllowClose" type="bool">False</property> </properties> </data> </webPart> </webParts> ]]> </View>
The above now let’s me set things like Title and Chrome.
Lastly, be sure NOT TO DO THIS in SharePoint 2010:
<View List="Project Documents" BaseViewID="50" DisplayName="Last Modified Project Documents" Name="Last Modified Project Documents" RecurrenceRowset="TRUE" WebPartZoneID="Right" WebPartOrder="2"> <![CDATA[ <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2"> <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ListViewWebPart</TypeName> <Title>Last Modified Project Documents</Title> </WebPart> ]]> </View>
The above will work fine in SharePoint 2010, but there will be some inconsistency and it won’t behave quite right. If you edit the web part, you’ll notice it’s missing a few of the options that the 2010 ones do.
This is really just a follow up to a post a wrote a while back and more of a reminder for myself. If you do a lot of backup/restore operations of content databases from production to development environments, you’ve no doubt run into the infamous:
Msg 33002, Level 16, State 1, Line 1
Access to table dbo.Versions is blocked because the signature is not valid.
I hate this particular error because it’s a little deceiving sometimes. In the past, I’ve attributed this error to differences in the patch level between your production and development environments. You can read all about it here.
But sometimes, when I do my standard backup/restore from my production server to my development server, I still encounter this error, even though my patch levels are the same. No amount of IISRESETS, SQL Service resets or WSS service resets makes any difference. What I find myself having to do is run the following command:
psconfig –cmd upgrade –inplace b2b -wait
After running the above, everything is all happy again. I needed to make a note of this more for myself because I can never remember what the command parameters are when I need it.
I’ve been doing a lot of work recently with SharePoint 2010 and the Content Deployment/Content Scheduling features, and it seems to me that not a whole lot has changed. According to the official Microsoft 2010 “Content deployment overview“, we still have to watch out for the following:
1. Always deploy to an empty site collection for the initial content deployment job – It doesn’t appear to be sufficient anymore to use the blank site template. The recommendation now is to use the <Select template later> option we now see under the Custom tab. I prefer to use the following powershell command:
New-SPSite -Url "http://silvermoon" -OwnerAlias "silvermoon\joeuser" -OwnerEmail ""
That will create a new site collection without applying a template.
I also wanted to note that I ran into some errors similar to what I had blogged about previously in 2007 (I’m surprised these still continue to be a problem). You can read more about that here. In particular, I was running into one error consistently:
Unable to import folder _catalogs/masterpage/Forms/Page Layout. There is already an object with the Id 62b662s-3344b-332bbs33-a334d-233k in the database from another site collection
I really couldn’t figure out what was causing this error. I had two web applications, with a single site collection in each, and I was creating the destination site collection without a template as prescribed by MS. Turns out, the very first time I created a site collection in my new web application, I had specified a template instead of selecting none. Even though I had deleted and recreated brand new ones several times since then, there were still residual traces of something, hence the error above.
The resolution for me was to detach the content db, and then reattach it. OR, delete my destination web application and start again.
Just wanted to note this for anyone else out there having a similar issue.
For those of you who do a lot of work with tools like jQuery and more specifically, the $ajax calls you can make, you need to be aware of tools like Firebug for troubleshooting the Params, Headers and Response you get back from the server. I find it especially useful when I’m working with a new plugin or tool like jqGrid, because it gives valuable (and time saving) insight into the calls that are being made from these plugins.
For Firefox, there is a great, absolutely must have tool called Firebug, but what about IE and other browsers? There will be scenarios where you’ll run into something that works in Firefox but not IE and so it would be nice to troubleshoot the ajax call directly from IE. Well, in the Firebug page, there is a link to the lite version that is supported by most major browsers, including IE. It’s officially called, Firebug Lite.
The quickest way to get this going is to download the firebug-lite.js file from here.
And then just link to it from the
element of your page.<script type="text/javascript" src="/scripts/firebug-lite-beta.js"></script>
Now once you load the page, the Firebug Lite component will append to the bottom of the page and it behaves much like the extension for Firefox. Give it a try!





