Thursday, April 12, 2007

TemplateRedirectionPage and ID as a Query String Key

We ran across an interesting issue today when using ID as a query string key for one of our custom web parts. Basically we have a RichHtmlField that pulls from a field that is defined in our base content type. In other words, there is a field that is defined on all of our page layouts. We then had a web part that expected a parameter of ID to do some work. Oddly, when we began passing in an ID the RichHtmlField began pulling in what looked like random content.

After looking into it a little more we realized that it was actually pulling the content from the list item with the specified ID in the query string. For instance, if we passed in 1 it would pull the content from whatever page happened to have an ID of 1. From the best I could gather it seems that the TemplateRedirectionPage translates the current request into a parameterized URL. It just so happens that it uses the ID key to determine what list item it should pull from the pages list. I tried to track it down for sure but hit obfuscation on the GetPathFromUrlValue within the TemplateRedirectionPage.

Although it is an easy fix, just change our query string key to something else, it was definitely one of the stranger ones I have seen. I hope in the future that they change this from a less commonly used key to something like _msID which would be much less likely to be used by external applications.

Labels:

Friday, March 09, 2007

Update an SPListItem without having to check it out...

Every once in a while it is necessary to make a change to a list item or other Sharepoint object without wanting to check it out, change the state, increment a major/minor version, etc. Fortunately the good folks on the Sharepoint team thought of this scenario… Basically there are two key components, SystemUpdate and RunWithElevatedPrivileges . First I’ll briefly discuss SystemUpdate.

SystemUpdate is a method on the SPListItem class that can be called in place of the Update method. Basically the main difference is that the SystemUpdate does not do a “touch” on underlying item. Additionally, there is an overloaded version that takes a Boolean parameter allowing you to specify that you do not want the version of the itemto be incremented. With this available we can safely update an item and leave it in the same state it is currently in. The next piece of the puzzle is how do you modify the item in the first place?

Typically as soon as you call the Update (or SystemUpdate) method it expects the user that the current context is running under to have the item checked out. Again, in some instances you just want to be able to update items (i.e. a batch update, etc) and have them in the exact same state as they are currently in. Fortunately, by executing the code using the RunWithElevatedPrivileges method we can get around the requirement of having to check out the item. Typically RunWithEelvatedPrivileges is used to perform tasks that require a higher permission level then the current user – as the name implies. Basically, you just specify a delegate to execute and it will run it under the account the current application pool is executing under (I believe).

That being said make sure that within you delegate you do not try to modify the items on the SPContext object itself as they will still be modified under that context’s user identity - forcing a checkout. Instead create a new SPSite and find the items you need from there – you can use the IDs from the current SPContext to find the corresponding items in your new elevated SPSite object.

Below is a brief example demonstrating making a change to the current publishing page that is executing:

SPSecurity.RunWithElevatedPrivileges(delegate
{
using(SPSite elevatedSite = new SPSite(SPContext.Current.Site.ID))

{
SPWeb elevatedWeb = elevatedSite.OpenWeb(SPContext.Current.Web.ID);
PublishingWeb elevatedPublishingWeb = PublishingWeb.GetPublishingWeb(elevatedWeb);

SPListItem currentItem = elevatedPublishingWeb.PagesList.Items[SPContext.Current.ListItem.UniqueId];

// Make some change on the current item
currentItem.SystemUpdate(false);

// Also remember if this change is being made on a GET request you will have to temporarily allow
//unsafe changes on the web. This must be done to the elevated web.

}
});

Wednesday, January 31, 2007

Updating Existing Content Types in Sharepoint 2007

I ran into an interesting problem today with Sharepoint 2007. Basically, I needed to be able to update a content type through the API rather then through the user interface. This is useful if you want to script updates from a development environment on one network to a stage or production environment or if there are a lot of updates that need to be made and you do not want to do them all manually.

So naturally I first went to MSDN and saw what they had to say. Basically, they recommended NOT updating the XML definition of the content type. Additionally they provided the following code snippet. (You can visit the article here.)

SPWeb web = GetSPWeb();
SPContentType myCT = web.ContentTypes["Specification"];
myCT.Fields.Add(Field1);
myCT.Fields.Add(Field2);
myCT.Update();

Seems, simple enough… but when I tried it didn't work. When you call the Update method on the content type, an exception is thrown stating that the content type cannot be updated because it is not associated with a list. So what does that mean?

Well after a little frustration and thinking about it, things started to make sense. When you define a content type you add field refs (unlike lists where you add fields themselves). Basically a content type is like the blueprint. It references the fields and stores the modified properties specific to that particular content type. So this lead to, how do you modify these delta field properties?

After looking a little more I saw an undocumented property called FieldLinks. Based on the name this contains the actual references to the fields that we want to update. The Fields property on the other hand stores a “merged” view of the fields. This means that the Fields essentially merges the changed properties with the field properties to give you a final view of what fields the content type contains.

Now say you need to make a field that was originally required no longer required, below is how you would do this.

SPContentType myContentType = myWeb.ContentTypes[“myContentType”];

// We will now index into the field links and set required to false

string internalName = myContentType.Fields[“fieldToUpdate”].InternalName;
myContentType.FieldLinks[internalName].Required = false;

// Finally we will update the content type, specifying true forces the change down to the
children
myContentType.Update(true);


That’s it, the change should now be updated in the web content type as well as any lists that use it (be careful as this overwrites any changes you made on the list version of the content type). Finally, as a disclaimer, I do not recommend using this to alter the content types that come with WSS or MOSS out of the box. These can change at any time and altering them can break other provided functionality inadvertently.

Labels:

Friday, December 15, 2006

Does More Abstraction = Less Developer Knowledge?

Technologies like the .NET Framework, ASP.NET, etc. are great tools that make my life easier every day. However, after conducting many interviews over the last year I can't help but wonder, do easier to use frameworks and development tools lower the collective IQ of the developer community?

In other words, does the "it just works" mentality held by many of the frameworks today make it too simple to just dive right in and begin development?

Don't get me wrong, managed languages and easy to use frameworks are great leaps forward. They allow developers to worry about implementing features rather than leaking memory and other low level details. However, there is something to be said to understanding exactly what goes on under the covers.

Although the ASP.NET 2.0 makes leaps forward in simplifying the task of developing a web application, I still think that as a developer it is my responsibility to take the time to learn the tools I use every day inside and out to the best of my ability. For instance, I was surprised to see how few knew the difference between a value and reference type, how forms authentication actually works, what is the difference between an interface and an abstract class, what does the "is" and "as" keyword do in C#, etc., etc. Furthermore, by not truly understanding the framework and language being used, how can we capitalize on all the features made available? Why write logic for appending paths together over and over when it is provided in the Path class?

Besides simply utilizing all the features provided in a framework, truly understanding what is going on will also become a life saver when things don't "just work." By not knowing exactly what is going on debugging turns into a guessing game rather then a systematic approach to resolve the problem. If changing value A does work then maybe I should change value B, oh, no luck, well maybe if a change Z and so on...

I look forward to the new advanced frameworks that will come down the line in the future. I know without a doubt that they will continue to make application development easier. However, I urge every developer to buy some of the advanced books out there and read them cover to cover. Pick up a C# 2.0 language reference and read the entire thing. I guarantee you will discover some useful feature you had never heard of before. Dive into Richter's CLR book and learn just what happens when an assembly is loaded and executed. Who knows, by really understanding the CLR that next "random" bug that only happens every 5th execution might not be such a mystery...

Labels: ,

Tuesday, November 14, 2006

Google PageRank Presentation

Just figured I would post it out incase anyone found it interesting. The presentation was from one of my current Masters courses. It goes over 2 of the papers written by the Google founders that detailed PageRank and the initial implementation of Google. You can download it from here.

Labels: ,

Thursday, September 21, 2006

How Yahoo sign-in seal works...

A colleague of mine recently pointed out a pretty interesting feature that Yahoo recently implemented on their login page. This new feature called “sign-in seal” is meant to help prevent phishing attacks by allowing users to upload a custom logo to the Yahoo login page. The principle is that if the user sees his or her custom photo that they know it must be the genuine Yahoo page. The interesting part was that once I set a logo up in Internet Explorer, it also showed up as expected in FireFox. Furthermore, the logo would still display correctly once the cookies on the machine were deleted. Seeing this led to the question; how are they doing it?

After playing around with it a while I think I found the “trick” they are using to not only span browsers but also survive cookie deletions on a single browser. This is done through a cookie like technology that Flash Player provides called shared object. Basically, a shared object is a cookie for Flash Player, however, shared objects do provide a few perks that a cookie does not. First, most users do not know how to remove them or even of their existence so they are a lot less likely to be deleted. Second, they cross browsers unlike cookies. Because Flash Player writes all shared objects, regardless of which browser the player is running in, to a single location, a developer can set a shared object in FireFox and consume it in the same way when the user opens their site in Internet Explorer. This technology has been around for a while, but props to Yahoo for utilizing it to make the “sign-in seal” seem that much “smarter.”

In closing, just to summarize what it takes to remove the logo from the login page:

1. Delete your cookies (Yahoo seems to use the shared object to rebuild the cookie if it is missing) and close the browser to get rid of any session cookies that may exist

2. Clear your shared objects (they are located at C:\Documents and Settings\%your user name%\Application Data\Macromedia\Flash Player\#SharedObjects\%some random number%\)

3. Now open the browser and go back to the login page and the logo should be gone

Monday, February 13, 2006

Learning .NET 2.0

I am currently in the process of learning .NET 2.0 which is why it has been a while since my last post. However, if you would like to follow along and get some good 2.0 references without having to filter through the bad ones, feel free to follow along...

Visual Studio 2005 specific references
.NET 2.0 specific references