Dev Team Assemble

Evil beware!
Add to Technorati Favorites

Archive

Category: .Net Framework

I came across this problem recently. Its a little strange and only happened once I changed my base webpart class to inherit from Microsoft.SharePoint.WebPartPages.WebPart. There seems to be two fixes for this problem that I implemented:

  • remove the XMlNamespace from class declaration
  • Use a .dwp file instead of a .webpart file in your feature folder

Technorati Tags: , ,

For the last little bit I have been working on learning how to package up all site infrastructure into a single feature.  All of this is pretty straight forward and I didn't really have any issues.....UNTIL  I tried to get lookup columns working.

Using CAML

I did some reading on the subject and apparently you can do all of this using CAML alone.  I came across a post from Josh Gaffery supporting this claim, but I simply could not get this working...so i gave up after spinning my wheels on it for longer than I wanted to.  Josh's approach is to use the list URL as opposed to the GUID that links the column to the source list and he has put up an update explaining it further.  Nonetheless....didn't work for me.

Using Feature Receiver

I knew that at this point I would have to take the feature reciever approach and modify the fields in place or create them.  I found two sources that both take different approachs to this problem.

  • Chris O'Brien has put together the a project on CodePlex that will create the lookup columns at activation time.  This actully sounds like a pretty good approach but unfortunately it didn't work for me.  I dont know if there is something wrong with my environment but I encountered a few errors doing this...things like the fields not rendering on the page layouts and getting the "The local device name is already in use. (Exception from HRESULT: 0x80070055)" error.
  • Waldek Mastykarz has a great post on creating the columns via code here.

Basically I took a hybrid approach to doing this by mixing the two approaches mentioned above.  I created a custom XML file that I deploy into the layouts directory and then use a feature reciever to read the xml content and create lookup columns based on this.  I also added a deactiving event to remove the fields when the feature is deactivated.  Heres the feature reciever code:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            using (SPSite site = properties.Feature.Parent as SPSite)
            {
                string contentTypes = null;
                string listName = null;
                string fieldName = null;
                string groupName = null;
                string staticName = null;
                string lookupFieldName = "Title";
                bool mult = false;
                bool required = false;
                string filePath = properties.Feature.Properties[
                   "ColumnDefinitionPath"].Value;
 
                XmlTextReader xReader = new XmlTextReader(
                  HttpContext.Current.Server.MapPath(@"~\_layouts\" + filePath));
                while (xReader.Read())
                {
                    if (xReader.LocalName == "Field")
                    {
                        #region Get values from attributes
                        if (xReader.MoveToAttribute("List"))
                        {
                            listName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Name"))
                        {
                            fieldName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("StaticName"))
                        {
                            staticName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Group"))
                        {
                            groupName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("LookUpField"))
                        {
                            lookupFieldName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("ExistInContentTypes"))
                        {
                            contentTypes = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Mult"))
                        {
                            bool.TryParse(xReader.Value, out mult);
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Required"))
                        {
                            bool.TryParse(xReader.Value, out required);
                            xReader.MoveToElement();
                        }
 
                        #endregion
 
                        SPFieldLookup lookup = CreateLookupField(
                          fieldName, groupName, required, mult, site.RootWeb,
                          site.RootWeb.Lists[listName], lookupFieldName, staticName);
                        if (contentTypes != null)
                            foreach (string s in contentTypes.Split(','))
                            {
                                LinkFieldToContentType(s.Trim(), (SPField)lookup);
                            }
                    }
                }
 
                xReader.Close();
 
            }
        }
 
        public static SPFieldLookup CreateLookupField(
          string fieldName, string group, bool required, bool allowMultipleValues,
          SPWeb w, SPList lookupList, string lookupField, string staticName)
        {
            w.Fields.AddLookup(fieldName, lookupList.ID,
               lookupList.ParentWeb.ID, required);
            SPFieldLookup lookup = (SPFieldLookup)w.Fields[fieldName];
            lookup.AllowMultipleValues = allowMultipleValues;
            lookup.LookupField = lookupField;
            lookup.StaticName = staticName;
            lookup.Group = group;
            lookup.Update(true);
            return lookup;
        }
 
        public static void LinkFieldToContentType(string contentType, SPField field)
        {
            using (SPSite site = SPContext.Current.Web.Site as SPSite)
            {
                SPContentType ct = site.RootWeb.ContentTypes[contentType];
                ct.FieldLinks.Add(new SPFieldLink(field));
                ct.Update(true); // will update children
            }
        }

As you can read from the above code the xml file would need to have a node like below for each lookup column:

 
<Field
         Type="Lookup"
         List="Access Type"
         Name="AccessTypeColumn"
         StaticName="Access_x0020_Type"
         Group="Infrastructure"
         ExistInContentTypes="THIS IS A COMMA DELIMITED LIST OF CONTENT NAMES"
         LookUpField="Title"
         Mult="TRUE"
         Required="FALSE"
        />
 

The Final Project

So here are all the pieces of my infrastructure project. Notice the placement of the lookupfields xml file...this is because the layouts directory is setup as a virtual directory for every sharepoint site and we can read files from there without a permissions problem.

12/TEMPLATES/FEATURES/myfeature/lists.xml this contains the source lists for the lookup fields
12/TEMPLATES/FEATURES/myfeature/contenttypes.xml this contains the content type definitions MINUS the lookup fields
12/TEMPLATES/FEATURES/myfeature/sitecolumns.xml this contains all the other fields included in the content types
12/TEMPLATES/FEATURES/myfeature/feature.xml the feature def
12/TEMPLATES/LAYOUTS/myfeature/lookupfields.xml this contains all the lookup fields that need to be provisioned

Hopefully this helps anyone who's been having problems getting this going. And a big thanks to Waldek, Chris and Josh for their posts.

Technorati Tags: , , , ,

Great post here with a fix/workaround. Essentially when you go to look in the windows .net framework directory that program is not there. In order to run this utility program you will need to use the Visual Studio command prompt that is in the Programs/Visual Studio menu.

Technorati Tags: , , , ,

I got the following error the other day (it has been shortened...):

"the web part you attempted to add no longer exists in the closed web parts gallery."

This was a pretty disturbing error...there was no real apparent cause for this problem...nothing in the logs. After messing about with it for a while I figured out that it was a dll version in the GAC that was causing the problem. On my dev box I had an updated version but the version in our prod envs is different.

It would be nice if the server was a little more helpful with its error messages....HTH if you come across it

Technorati Tags: , , , ,

From November 2008:

Whew...its been a long week and its only Thursday. This years conference was much the same as last years with the exception of being held in various portions of the Mandalay Bay convention center as opposed to on one floor. This made for lots and lots and lots and lots of walking. But I'm still young (yes i am) so it makes for good excercise to walk off all the food they shovel in your mouth.

Most of the sessions I attended were really good with the exception of a couple. I wouldn't blame the speakers because these problems were mostly due to technical issues like the computers not working, the projectors broken or feedback in the presenters microphone sort of thing. All in all there were some great things presented this week.

Some of the sessions that really stuck out were:

Kimberly Tripp - Index Internals and Usage
This was a great session that talked about thins like SQL Server Statistics, Query Optimization, Types of indexes, diminishing returns on performance, etc. Of all the session I think this one stood out the most and because it is probably the most relevant for me right now being one of the "SQL Server DBA" for my company (Christie Digital). I say it that way because its a committee based DBA :)

Rick Strahl - Using WCF for JSON and REST Services with ASP.Net

Great session....last one of the conference for me so it really sticks out but essentially this covers the next gen replacement for ASMX or first gen webservices in the .NET Framework.

John Papa - Practical Strategies with the Entity Framework

For me this was an introduction to the Entity Framework that was released in VS 2008 SP1. John did a great job of quickly introducing the technology and getting on to the meat and potatoes of what we were there to discuss. There was a good discussion on how to use the IDE to build the data mappings and what happens after you make changes to the backend server, which coinceidently can be any data source...not just SQL as Linq to SQL supports.

Things I would change...(and only because its my blog and I can say whatever I want!!!)

...the time between sessions was ridiculous...one hour or in some cases and hour and a half is just way too long. They could have added an extra session or two to the day. I realize they want you in the expo hall but they could have extended the day to facilitate that or leave it open all day and then some people may skip a couple of sessions here and there to go and see what the vendors are offering. this was my gripe last year and its my gripe this year. Its probably going to be the thing that keeps me from going to this in the future.

...provide video or podcasts of the sessions so we can take in the whole conference...even the sessions we didn't get to go to. I see there point about this being intellectual property and the speakers are consultants and this is their livelyhood but I mean if they are willing to teach this at a conference...and we pay to see it...shouldn't we be entitled to review this information after the fact? Maybe they will supply it on their site (i heard they were recording the sessions this year).

...ease up on the food. Damn, there was too much...I ate too much...I felt stuffed the whole time...I guess this is really my fault! Okay dont change that :)

Technorati Tags: , , , , , ,

Heres a simple way for you to view your GAC in its naked state, go to the following registry location:

HKLM\Software\Microsoft\Fusion, once there create a DWORD value named "DisableCacheViewer" and set it to value 1.

Easy!

Technorati Tags: , ,

Well I finally found a solution to this. I had been having this issue for a while. I felt shame...but alas no more!!!!!!

Check out this blog http://www.elumenotion.com/Blog/Lists/Posts/Post.aspx?ID=23

The fix to this is so easy its almost embarrassing...I mean its not even a fix. Essentially this is what you do:

  • In your Visual Studio IDE > Open Tools Options.
  • Check Show all settings if needed and locate Enable Just My Code (Managed only) .
  • Uncheck this box and click OK.
  • Attach to your process
  • Open the modules window to ensure that your module appears and that Symbols have been loaded for it.