| Michael's profileMike's RavingsBlogLists | Help |
|
April 24 Ajax enabled Web parts SampleAjax enabled Web partsI have run into numerous questions and comments on AJAX enabled web parts and seen way to many partial answers that get folks with sight of a functional web part only to dash their hopes. So I am going to throw my hat in the ring and post some code here from one of my AJAX enabled web parts which has been in production for 7 months now. Like everything else, there are different ways to do it so don’t think mine if the only way. It is just one of the ways that works. I took some liberties here in assuming your current level of expertise in coding web parts and AJAX. If further explanation is needed, please feel free to post some comments and I can adjust this post. First, you can only have 1 Script manager object per page. A good way to do this, embed it in your master page. Sooner or later someone is going to create another AJAX web part and if you allow folks to push script managers into web parts you will end up with a new web part that breaks yours and theirs. It is easier to just put it in once in the master page and tell your web part developers to refrain from doing so in their code. Next, use the oninit function as the point to set the async triggers and call the EnsureUpdatePanelFixups function I will include further down. Creating Update Panel object I created a helper class to set the values on the update panel and other controls. Here is what I did for creating my Update Panel. This function is called in the onInit class. public static System.Web.UI.UpdatePanel CreateUpdatePanel(string id) { System.Web.UI.UpdatePanel updatepanel = new System.Web.UI.UpdatePanel(); updatepanel.ID = id; updatepanel.ChildrenAsTriggers = true; updatepanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
return updatepanel; }
This function is called in the onInit as well. It will override the usual javascript submit functions in MOSS.
private void EnsureUpdatePanelFixups() { if (this.Page.Form != null) { string formOnSubmitAtt = this.Page.Form.Attributes["onsubmit"]; if (formOnSubmitAtt == "return _spFormOnSubmitWrapper();") { this.Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();"; } } ScriptManager.RegisterStartupScript(this, typeof(ProcessSearch), "UpdatePanelFixup", "_spOriginalFormAction = document.forms[0].action; _spSuppressFormOnSubmitWrapper=true;", true); }
Finally once both the previous code blocks have been called: //Search submit button async postbaclk trigger AsyncPostBackTrigger UpdatePanel1SearchPostBackTrigger = new AsyncPostBackTrigger(); UpdatePanel1SearchPostBackTrigger.ControlID = BTNSUBMITSEARCH; UpdatePanel1SearchPostBackTrigger.EventName = "Click";
AsyncPostBackTrigger UpdatePanel1WorkflowSelectPostBackTrigger = new AsyncPostBackTrigger(); UpdatePanel1WorkflowSelectPostBackTrigger.ControlID = DGWORKFLOWLIST; UpdatePanel1WorkflowSelectPostBackTrigger.EventName = "ItemCommand";
UpdatePanel1.Triggers.Add(UpdatePanel1SearchPostBackTrigger); UpdatePanel1.Triggers.Add(UpdatePanel1WorkflowSelectPostBackTrigger);
This last section will create async post backs triggers for the specified control events within the panel. Keep in mind, I specifically set the ID for the control and the event that will kick off the async postback. In this example it uses the Click event of a button in the update panel and the ItemCommand event from a datagrid that is inserted in the panel. The controls referenced here MUST be in the update panel April 02 Good ways to screw up your WFEs part II imagine this will be a multiple part posting as off the top of my head, I think I could write an 1,110 page book on this topic. I got a new one the other day which I had never tried, but really, when it was shown to me, it scared the crap out of me. One of the biggest things to take from these posts, have a solid and TESTED Backup/Recovery process in your organization. Do NOT just give it lip service, write it on paper, file it away (ironically probably in MOSS), and wait till your first major failure to fully test it. I will give you a real life configuration I have worked with which would be majorly impacted. Adjust to your own real world scenario. So, let’s assume you have a 5 server production MOSS farm, 2 A/P clustered SQLs, 1 index, 2 WFEs. You have 3 web apps in your portal. You have a custom membership and role provider. You have 4 or 5 custom web parts. Maybe a server control or 2 you have thrown in that uses an entry or 2 in your web.config app settings. For fun, let’s throw in a customized CAS file. You also have some SSL settings you had to configure in IIS as well as some Metabase configuration you had to screw with since you are using host headers across SSL. Maybe your did some IPBinding, who knows . WFE1 is being a PITA. You get royally annoyed by the WSS Services misbehaving, or you are getting a freaky error on that box, or you are bored and a masochist so you are playing with your production configuration. For whatever reason, you decide to stop and start the WSS services on that WFE. You click stop. Give it a second, click start. Your memory issue or whatever issue prompted you to restart that service disappears. You are happy, for the moment. Then your custom web parts start kicking off errors. Probably security errors. As a matter of fact, you are getting sporadic errors where users cannot even log into your web applications through FBA anymore. Most likely, you get issues where the server cannot resolve the url to the web apps anymore. All hell is breaking loose. So what happened? To see what this actually did, grab a virtual with MOSS on and at least 1 MOSS web app. Open ISS, open a windows explorer session to the inetpub folder for your web apps. Now that you’ve got your window open, go into Central Administration and stop the WSS services. You will see your IIS web apps totally disappear along with the inetpub folder for your web apps in windows explorer. Start the WSS Services. They reappear. Man, how did MOSS do that? Geez, it is smart you say. Not really, it pulled the information it needed out of the MOSS farm configuration DB. When you reactivated WSS Services, it rebuilt the web applications and your inetpub folder(s). Back to your production scenario. You had those SSL settings, the metabase settings for your host header/SSL setup, your web config and Code Access security mods. Then you start to panic as you realize, MOSS rebuilt those web apps using the MOSS configuration DB. Your mods to IIS, web.config, CAS, etc, MOSS knows absolutely nothing about those. You make those settings totally outside of MOSS. In essence you just blew them away. What you have created is an opportunity to discover just how good your backup/recovery process is for the file system of your WFEs. If you restart your WSS services through the central administration site, keep in mind, MOSS will rebuild the web applications on your WFE from the MOSS configuration DB. Any modifications you made outside the realm of MOSS, will be gone. If you have not taken steps to back up your metabase and your file system mods you will now get to do them again, manually. So, a couple lessons here. First, backing up MOSS involves more than just your DBs. If your DBs are all you are backing up. You are probably missing something. Second, even seemingly miniscule tasks like turning on and off WSS Services can have MAJOR impacts to your farm. Giving an untrained individual access to central admin and throwing a shiny new “Sharepoint Administrator” title on him/her, is akin to handing them a case of nitro glycerin, labeling them a demolitions expert. Train your staff for the role and once trained they will give you point number 3….ALWAYS test even simple actions like this on a disposable test system BEFORE production. Not just a VPC sandbox, but a fully fledged test system that mimics production. A single server sandbox and a multi-server farm behave differently in many areas. If you have a multi-server production farm and you do all your testing/validation on a single server sandbox, you will have issues. Sooner or later you will create issues on your production environment, and they will be real fun to debug. You can virtualize the entire test system, but create one and use it. Fun with MOSS Resource filesHow many times have you gone through MOSS and looked at labels, descriptions, grid headers, etc, on the standard MOSS UI and thought, “Man…what I would not give to be able to change that wording!”? After attending an architecture class in Atlanta with Bill English, my mischievous streak got the better of me, and I set out to figure that out myself. I started with the “Application Management” page in central administration, otherwise known as applications.aspx. I had assumed that the text was maybe somewhere in the DB. Given the Central admin content DB is actually not that large, I dove in and set out to find the point where this text constant was defined. To my dismay, I only found the text from the navigation/menu bar. This text can be changed through the MOSS site settings UI in central admin, I would not recommend running UPDATE queries directly to the MOSS DB. While I am on that topic, keep in mind this expedition was conducted on a virtual, please do not crack open the DB for fun on a production server. This may seem like extreme common sense however, we all know common sense is not always that common. If you crack open the MOSS DB on your production server and screw it up by making what you think is a minor change, well do not expect MS to be too helpful when you call support. Back to the hunt, After failing in the DB it occurred to me, that maybe just maybe there was a config/resource file guiding these constants. After all, MOSS is available in a ton of languages, and I could not imagine MS embedded all these text constants into the binaries for MOSS. To my surprise, indeed, MS has embedded a TON of those string literals your find throughout MOSS in a series of resource files which are located in the inetpub\wwwroot\wss\virtualDirectories\<web app dir>\App_GlobalResources folder. The one I was looking for, “Application Management”,was in the SPAdmin.en-US.resx file. So I spent a few minutes having some fun, modified the “Application Management” to “Application Manglement”. Changed a mess of the page descriptions, link text, even removed the “Zones” text and renamed it to “Incoming Vectors”, a term an instructor mentioned in a class which better describes the use of those values. So, in practicality, is there any use to this beyond having some fun and getting a little more insight into lower level design in MOSS? Well, I could certainly see some of my clients, particularly those who were more hung up on some of the wording in MOSS taking a good look into this. There are a LOT of resx files, A lot of values to modify. Is this something you would want to do? Maybe, but keep in mind if you did decide to take this and put it to use in a productive way: 1. Back up your original resx files. 2. You will need to modify these on each WFE. 3. You will need to add these modified files to your backup/restore planning. One more “little” thing. I would not in the slightest expect MS to be in a position to have tested what would happen to their application when folks modified the resx files. I have not tested this full fledged in a large farm, and I cannot guarantee that there is not some embedded code in the bowels of MOSS, that would go beserk when you modify these values. I would expect that you would be fine, after all this is what resx file usage is for, and embedding resx values (vs keys) into your app sort of defeats the purpose of having one. However, MS still hires humans to do their development, so I cannot guarantee that they always follow best practices. That being said, it is awfully fun to mess with March 25 SharePoint Chaos TheoryDespite its bugs, limitations, and quirks, I truly believe MOSS is one of the best solutions out there for building collaborative and application portals. When properly utilized, it can empower a workforce to work together like they have never before. The key term there being “properly utilized”. When not properly planned, you can end up with the nastiest rat’s nest and corporate money pit you have ever seen. MOSS is not something you just throw up and go with it needs to be planned out, and documented ahead of time, before you even think of installing it on any server? The following are some of the critical steps/questions you need to sort though in earnest before embarking on an installation. 1. What features do you want? This seems like it would be an easy enough question. However it is not always. It all depends on WHY you want a portal? Are you looking for a corporate dashboard? A document repository? A system to manage workflows? Collaborative team sites? All of the above? None of it? Many clients I have worked with go out and buy licenses without answers to these questions. The problem is you can end up majorly underestimating or overestimating costs without these questions answered? Standard and Enterprise editions for example, are priced very differently. You cannot possibly know which version you want if you don’t know. 2. Hardware Hardware is one of the most frustrating components of any MOSS engagement I have been on. I frequently find myself having to push hard for multiple Web Front ends, application servers, Clustered DBs. I my opinion, if you are intending your portal to server as your company’s collaborative backbone, document repository, or anything more than just a general curiosity, you cannot afford to cheap out on hardware. A single server implementation for a production environment is simply unacceptable and if that is all you have a budget for, you really have to accept that you cannot afford a SharePoint solution. The recovery time for a single server, even with proper backups, can be significant. The smallest production environment I would suggest would be a dual WFE, with a dual SQL 2005 Active/Passive clustered backend. The DB clustering is the more critical because MOSS is the DB, All your content, configuration (minus whatever has been customized to the web.configs), everything is in the DB. If you have no DB you have no MOSS. Plus rebuilding a WFE is significantly easier than rebuilding a SQL server and reconfiguring all your permissions. Dual WFE’s are critical for multiple reasons, first of all, sooner or later you will need to patch a server. Given MS’ history with patches, having a single machine is a significant risk in this area. If the patch hoses your box, then your entire portal is gone until you repave and rebuild the web front end. Also, unless you have the simplest of portals, you will need to configure search (crawling and indexing), MySites, and Profile imports among other things. Throw is workflows, custom web parts, branding, etc and you quickly begin to overwhelm your single WFE. Also, once you have multiple WFEs installed with load balancing, adding additional servers, application or WFE, becomes even easier. It is better to take the hit and pony up the cash for dual WFE’s. BTW, I have many clients running MOSS in virtualized environments successfully. The general way to go is virtualize WFEs and app servers, and leave your SQL boxes are dedicated non-virtualized machines. 3. Analyze your user base!! Like any web application, you need to look long and hard at your user base and how you plan on organizing them. I cannot count how frequently a MOSS engagement ends up getting stalled because of this item. So flash forward…you have your dream portal, it is full of content. How do your users access the content? How are they grouped? Do you want a security free for all with users accessing all content? Do you want to end up with massive inconsistent, individual user permissions assignments, and a nasty security model that nobody can figure out or clean up? You need to plan this out ahead of time, then you need to take a long hard look at your AD/LDAP/SQL auth model and verify it supports what you want to do. At least 50% of my MOSS engagements have resulted in a total re-architecture of a clients Active Directory structure.
A quick note on AD re-architecture, if you are going to do this, then you need to do it right. You need to think enterprise when you do it not just fitting your AD structure into a MOSS shaped hole. You can easily get your AD folks into a homicidal rage when you make 200 AD groups that can only be used within MOSS, then follow up 3 months later with 400 more for your exchange groups, and 300 more for an in house web application. 4. Map it out Crack open Visio, or something like it, and draw out your portal. Draw out your site collection(s), your portal structure, your MOSS security groups, how they map to your authentication/role providers. This is critical to sanity check your implementation. With the portal structure mapped out, the security groups defined, customizations like workflows, web parts, etc all defined (at a high level) in a single document, you can get the full picture of what you are putting together. You can identify critical flaws, pain points, etc. Without this, you are shooting in the dark. 5. Define Governance Microsoft has some awesome templates for this (http://technet.microsoft.com/en-us/office/sharepointserver/bb507202.aspx ). You need to know who does what In the implementation. What your support contract is with the user base, who can create sites, who will manage MOSS from central admin, who will serve as site owners. It is also a good idea to put together a MOSS strategy team to help guide where you want to go. The best maintained and utilized MOSS installations I have seen are also the best governed. This is not a coincidence. 6. Plan the installation Do not just insert a CD and go for it. You will screw it up. You will have a set of service accounts (if you even make the proper service accounts) that expire 3 months down the road and shut down your SSP. Or your service accounts will not have the correct permissions. Trust me, it will get screwed up and 3-6 months down the road you will end up reinstalling and re-configuring everything or limping along with an unreliable and totally unsecured MOSS farm. Secure farms do not happen by accident or chance. They happen because someone took the time to properly plan them. Do your research, buy the MS Press SharePoint Administrators Companion, or hire a Gold Certified consulting partner to assist. 7. Know when you are in over your head The final guideline, know when you are in over your head. To be clear, I work for a MS gold certified partner. Since MOSS was Beta, I have run through dozens of architecture sessions and installs. My company has spent a lot of money to train me and my co-workers as has any gold certified partner. Your average IT department is not going to have the will or budget to train their folks to that extent, especially when their staff will likely do 1 or 2 production MOSS installations at most. Creating an enterprise portal is not an insignificant task. It can have a huge positive impact on a company or it can have absolutely no positive impact depending on how it is planned and architected.
February 28 Adding LDAP Groups to MOSS groups amended Continuing with the previous article I ran on programmatically adding LDAP groups(Domain Groups) to MOSS groups I ran into a fun little bug with MOSS that has the potential to really hose you on this effort. 2 things, make sure your LDAP groups are prefixed with the name of your ROLEPROVIDER name. This will need to match exactly the value you have in your web.config. Now once you do this the bug comes into play.
MOSS will do next to no validation on your group and username. It will certainly NOT call your providers to verify the Role name exists. In fact as long as you get the prefix of your custom membership OR custom role provider name in there, it will assume it is valid. So you can enter all sorts of groups and users that don't exist. The important thing here is you are 100% certain the names you enter are valid and that you utilize the ROLEPROVIDER prefix and not the MEMBERSHIPPROVIDER name. Now if you have been bitten by this bug, before you go on a killing spree, I do have some code to assist you in correcting this. Drop me a line and I can post it. January 29 Search Customization: Adding Custom Content Type Meta-Data to Advanced Search (via SSP)As many things in MOSS there are numerous ways to do something, and numerous levels. In this entry I am going through setting up a search scope in my SSP (vs. doing one local on a site collection), mapping columns from a custom content type, and making a managed property searchable in an advanced search control. This is VERY simplistic but hopefully, you can take the guide given hear and apply it to whatever you need to do. Please check out the links I reference on the end of this article. These guys have some great and more in depth info on parts of this process. 1. Create and deploy Custom Content type 2. Create Search Scope(s) a. Central Administration/SSP level i. Set up the Search scope in the SSP administration 1. Click “Search settings “ link 2. In the Scopes section click “View Scopes” 3. Click “New Scope” 4. Enter all valid info and click “OK” 5. Click on you new scope and click “new rule” 6. Enter your rule and click OK. 7. Repeat #7 as many times as you need to complete your set of rules for the current scope. ii. Once search scope is set up you will need to enable it on your various site collections that will need to utilize it. 1. To do this, do into the site collections settings menu (go to your root site, and in the site actions drop down go to all settings). 2. Click Search Scopes link (your new scope will be in here marked as “unused”) 3. Click on the link that says “Search Dropdown” it is in the search scope listing on one of the section titles. 4. Check the box next to your scope, set any appropriate order/default settings and click OK 3. Set Managed Properties for Content Type Columns a. Navigate to the SSP Administration site, click “Search Settings” b. Next click on the “Meta data property mappings” link c. Click on “New Managed Property” d. Enter the properties friendly name (no spaces), description, and select the data type e. Then click the “add mapping” button f. Find your property in the listing, select it, and click OK g. Check the search scope checkbox if you want this managed property to be used in defining search scopes. h. Click OK 4. Modify Advanced Search Web part to allow search on Managed properties a. Open page that contains the advanced search web part b. Edit page, on the advanced search web part, modify shared web part c. Under the properties section, find the entry in the Properties text box. i. T o make your life simple, copy it into some type of XML editor that will format it for you. ii. First, in the “propertyDefs” node, insert and entry for your Managed Property iii. Next, add it to every valid Result type (see the result types node iv. Copy your updated text into the Properties entry for the advanced search web part. You should now be able to search on your property (make sure you run a full crawl from your SSP site to be safe.
References 2. http://blogs.msdn.com/cjohnson/archive/2006/10/19/moss-search-scopes-missing-in-action.aspx December 18 MOSS Load Balanced URL
One of the fields least understood by someone first coming into MOSS is the Load Balanced URL which if a field required on the “Create Web Application” screen from central administration. It will default to the current server URL and port. If you have worked on a single web front end install, chances are you didn’t even give this field a second look. Chances are of you added another WFE to your farm, you suddenly scratched your head and murmured some type of expletive when you hit your second WFE and found all the links pointed back to your first WFE and no matter what you did you could not fix this. Taken in it’s simplest, most basic explanation what you put in this field, is what all links on MOSS will be prefixed with. So if you have DocumentA.doc in the Shared Doc lib off of your main site collection. Your URL to it will be http://<Load balanced URL value>/Share documents/DocumentA.doc. So why do we want this? What purpose does it serve? It is all around how NLB works and how to make the most of it. Without this, all links would end up being based on the local server. Any links you shared would jump to the server, not through NLB. In many, if not all you should not even be able to hit the server directly this way. If you could, under the scenario above, if the server you were hitting suddenly became overloaded, you would be stuck there throughout your session. However, since the Load Balanced URL bounces you back to through the NLB URL, this allows you NLB to properly balance the load. There is a lot of info out there to help you out in NLB I have put together a series of links below which hopefully help you out in your search. Happy hunting! Link(s): - TechNet Creating a MOSS web application http://technet2.microsoft.com/Office/en-us/library/5ed10d1c-ffdf-4651-b7b6-cac1de6f9ee11033.mspx?mfr=true - Technet MOSS Configure Alternate Access Mapping http://technet2.microsoft.com/Office/en-us/library/be9d31d2-b9cb-4442-bfc6-2adcdbff8fae1033.mspx?mfr=true - What every SharePoint administrator needs to know about Alternate Access Mappings (awesome series) http://blogs.msdn.com/sharepoint/archive/2007/03/06/what-every-sharepoint-administrator-needs-to-know-about-alternate-access-mappings-part-1.aspx - MOSS Farm, Virtual server and NLB http://www.sharepointblogs.com/aaronrh/archive/2007/04/13/sharepoint-farm-virtual-server-and-network-load-balancing.aspx December 07 FBA (Forms Based Auth) has it's catchesI have set up a few farms now with FBA hooked into various sources from SQL to Novell LDAP. I can absolutely say you need to CAREFULLY evaluate your requirements against your need for FBA. A lot of the docs (especially marketing) make this sound like a trivial, just plug and play issue. It is far from the truth. If you are running on a tight timeline and do not have a lot of time to investigate issues you WILL run into you need to stay with AD auth if it is an option. While I would have some serious questions for the MS architect(s) who put together the FBA piece with MOSS, the purpose here is not to flame MS, but to make sure you are completely aware of the implications of your choice to utilize non-integrated auth. There are many cases where FBA is the only option, and plenty of examples where it has been used successfully on MOSS implementations. Just be aware, if you have bought into the marketing, thinking FBA is a simple issue, and have serious non-flexible requirements on at least 2 items on this list, well it is very likely you have grossly underestimated the time required to get the implementation done. Let’s examine some of the common ones I have run into: MY Sites The word I have gotten from some at MS is this is impossible to have with FBA. I have however found a few blogs which helped me get this up and running. It involves setting up MySites and your SSP site to use FBA however. This creates some serious usability issues with your SSP site that you need to work though.
Search At the current time (MS says this may be fixed in SP1), search will not crawl FBA content. Which means even if you have your sites set up with a second AD enabled zone to allow search to crawl that content, it will not crawl any portion of the MySites, since they are exclusively set up under FBA.
Office Integration This is a huge deal for many clients. A lot of the compelling office integration features with MOSS disappear or totally screw up when you keep client integration turned on with FBA. If your company figured they would get MOSS and then invest in upgrading their office suite to 2007 to take advantage of all the cool integration features, then they do NOT want to use FBA. If they do, they might as well not upgrade their office if the MOSS integration was a major part of the upgrade. Membership and Role Providers MOSS ships with some Membership and Role Providers, the problem is once you get out of MS built products they are of limited value. As an example a recent implementation I worked on with FBA, involved a Novell eDirectory system. A quick search will find numerous folks using this with the default LDAP provider. However, when you have a Novell eDirectory system with SSL enabled, that does not permit anonymous connections, well get ready to sling some custom membership and role provider code. The good part is, it is relatively easy to do (once you figure out what you are doing) and you get a tremendous amount of control over the auth, and role system. In terms of security though, one thing that makes managers nervous, the membership provider contains a method “ValidateUser” which passes the username and password for all users into the roleprovider, a perfect place for a retarded coder to place some bad logging code. I could easily fill 5-10 pages on this coding process and all the fun little issues you can run into, if you do run into issues, feel free to post a comment here and I can give you more info. Profiles This is one of those little items that can sting a bit. MOSS needs to have unique names for your user accounts. So unlike the imports you run for AD, it will append the name of your role and membership provider to the beginning of your users names “MembershipProviderName:Username”. This can be one of those little things that bugs you sponsors a bit, especially when they see it on the dropdowns on the top right of the screen or when you see it in the user profile screen. Profile Import Good chance if you have had to go the route of the custom membership and role provider, that the built in profile Import for MOSS won’t work for you either. If this is the case you will be writing your own. Not too bad of a coding effort but by the time you get to coding this you will find you are pretty deep into your timeframe and still have a mess of things to sort through.
Like I said, FBA can and does work. It is just, depending on your specific requirements, it is not always the simple tasks it seems at the get go. If you are in that boat, hopefully you get some guidance on where you need to start researching. November 20 Programmatically Adding LDAP groups to MOSS groups
I have seen a few posting for this on importing users or AD groups into a MOSS security group. For the most part it is very similar to the AD groups , however there are a couple little special things that can make it interesting and cost you a little time. Rather than annoy you with a lot of chatter, I have included functional code below to help you out. One critical thing, the groups MUST be prefixed with the LDAP provider name. This is the equivalent of the AD domain so when you get over the annoyance and stop to think about it, it makes sense.
So let’s say your LDAP provider name is: “ACMELDAP” and your group name in the LDAP system is ACME_Managers. You would enter “acmeldap:ACME_Managers” as the LDAPFullRoleName. LDAPRoleName is the field for the friendly name. Anyway, I hope this helps someone out there out. Shoot me a comment/question if you come across a better way to do any of this.
public bool AddLDAPRoleToMossGroup(string sharePointSiteURL, string LDAPFullRoleName, string LDAPRoleName, string MOSSGroupName) { try { SPSite StationWorkspace; SPWeb StationWorkspaceWeb; SPUser LDAPGroupUser;
StationWorkspace = new SPSite(sharePointSiteURL); StationWorkspaceWeb = StationWorkspace.OpenWeb();
SPUser spUser = GetSPUser(LDAPFullRoleName,LDAPRoleName, sharePointSiteURL);
if (spUser == null) { spUser = CreateUser(LDAPFullRoleName, "", LDAPRoleName, "Added by SharePoint utilities", sharePointSiteURL); }
foreach(SPGroup curGroup in StationWorkspaceWeb.SiteGroups) { if (curGroup.Name.ToUpper() == MOSSGroupName.ToUpper()) { //Add and update group with new user curGroup.AddUser(spUser); curGroup.Update(); } }
return true;
} catch (Exception ex) { CommonFunctions.WriteToLogFile(APPNAME, "AdminFunctions:AddLDAPRoleToMossGroup - sharePointSiteURL: " + sharePointSiteURL + " LDAPRoleName: " + LDAPRoleName + " MOSSGroupName: " + MOSSGroupName + " Error:" + ex.ToString()); return false; } } } private SPUser GetSPUser(string LDAPFullRoleName, string strLoginName, string strSiteURL) { SPUser spReturn = null; SPSite spSite = null; SPWeb spWeb = null; try { //Open the ShrePoint site spSite = new SPSite(strSiteURL); spWeb = spSite.OpenWeb();
//Check to see if user exists spReturn = spWeb.AllUsers[LDAPFullRoleName]; } catch (Exception ex) { CommonFunctions.WriteToLogFile(APPNAME, "AdminFunctions:GetSPUser - Error: " + ex.ToString()); return null; } finally { spWeb.Close(); spSite.Close(); }
return spReturn; }
//Creates a new user private SPUser CreateUser(string strLoginName, string strEMail, string strName, string strNotes, string strSiteURL) { SPUser spReturn = null; SPSite spSite = null; SPWeb spWeb = null;
try { //Open the SharePoint site spSite = new SPSite(strSiteURL); spWeb = spSite.OpenWeb();
//Assign role and add user to site SPRoleAssignment spRoleAssignment = new SPRoleAssignment(strLoginName, strEMail, strName, strNotes);
//Using Contribute, might need high access SPRoleDefinition spSPRoleDefinition = spWeb.RoleDefinitions["View Only"];
spRoleAssignment.RoleDefinitionBindings.Add(spSPRoleDefinition); spWeb.RoleAssignments.Add(spRoleAssignment);
//Update site spWeb.Update(); spReturn = spWeb.AllUsers[strLoginName];
} catch (Exception ex) { CommonFunctions.WriteToLogFile(APPNAME, "AdminFunctions:CreateUser - Error: " + ex.ToString()); spReturn = null; } finally { spWeb.Close(); spSite.Close(); }
return spReturn; November 15 Fun MOSS Quirks: Custom Site templates PageLayoutURL This particular one will nearly drive you to suicide. So you develop a sweet site and decide, hey, I am going to save this out to a site template (stp) file and deploy it out to my other MOSS farms. You got a nice welcome page that is created with a custom page layout you developed. You include your stp file(s), custom master pages, custom CSS, images, custom page layout(s) and other branding features in a wsp and deploy them to your other MOSS farm and activate the features. Everything is nice, then you create your first site using one of the templates and all hell breaks loose. Your custom welcome page will not load, in your researching you take a look at your page layout and associate content type. It is then, and only then you find...your page layout on your other server farm is piinting back to the original site you developed on. So what the heck is going on?
What's going on is a field in MOSS called "pageLayoutURL". If is found via the page.ListItem[FieldiD.PageLayout] call. It contains a freaking fully qualified URL to the original site "http://" and all. Apparently, this field passed MS' testing process. It can create some serious issues for your site.
As part of any feature rollout, I have included some new code to help me out in this. I pulled it off another blog (as soon as I find the URL I will post that fellows URL here so he can get proper credit).
First you need to create a site using the sp file you pulled over in your feature. Next, you need to be sure publishing is turned on. Next you run the code I will include in this post against that site (it is fugly POC code so if you need to clean it up for your purposes, feel free). Basically, it cycles throught every page in a site and reset this value to the current site URL. For my feature, I actually created some script that will provision a new site usin gthe template, turn on publishing, execute the fix code, turn off publishing, and save new template from the updated site and blow away the old template.
sample code:
PublishingPageCollection pages = publishingWeb.GetPublishingPages();
foreach (PublishingPage page in pages) { string pageLayoutUrl = (string)page.ListItem[FieldId.PageLayout];
utilities.WriteToLogFile("MOSSFunctions", "FixPages: Now Checking: " + page.Name + " Layout url is at: " + pageLayoutUrl);
//if pageLayoutURL is null or empty or page layout url index of "/catalogs" < 0)
if (string.IsNullOrEmpty(pageLayoutUrl) || pageLayoutUrl.IndexOf("/_catalogs/") < 0) { utilities.WriteToLogFile("MOSSFunctions", "FixPages: Condition one tripped"); continue; } SPFieldUrlValue url = new SPFieldUrlValue(pageLayoutUrl);
string temp = publishingWeb.Web.Site.ServerRelativeUrl.TrimEnd('/') + url.Url.Substring(url.Url.IndexOf("/_catalogs/")); temp = publishingWeb.Web.Site.MakeFullUrl(temp);
if (url.Url.ToLowerInvariant() == temp.ToLowerInvariant()) { utilities.WriteToLogFile("MOSSFunctions", "FixPages: Condition two tripped"); continue; } Custom Membership Provider "Server not operational"You have coded your own Membership and Role providers to manage the authentication, role validation, user information, etc to a non-AD LDAP data store. You have utilized the standard DirectorySearcher, Directory,Entry, etc classes from the System.DirectoryServices namespace. The installation on central admin, the windows auth site, goes smoothly and you easily verify communication between these sites and LDAP as you add a couple LDAP users to the extended FBA site to make it possible for you to log in to that site and add other users/LDAP groups. You attempt to log into the FBA site and despite being a high level user your LDAP authentication fails. You check the logs from your membership provider and find that all attempts to access the LDAP server return a “server not operational” error. As an additional hint, you can look in your SYSTEM event log and find an exception kicked out by “Schannel”, just once. It generally will not repeat until you reboot the server. The text of that exception will be something like: “System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational. Also, schannel event 36882 is logged to the event log: "The certificate received from the remote server was issued by an untrusted certificate authority. Because of this, none of the data contained in the certificate can be validated. The SSL connection request has failed. The attached data contains the server certificate.". The code failing is the exact same code that runs fine on the other 2 sites (CA and non-FBA site) and you have installed the certificate for the SSL communication on your server.
There are a couple circumstances that lead to this exception. The first thing to understand is this, the actual thread that is accessing the membership provider, on the central administration and Windows integration security site, is running under the logged in user, and NOT one of the MOSS service accounts. However, when you set up FBA on the 3rd site, in IIS is turned off integrated security, and enabled anonymous access. As a result, when you attempted to log into the FBA site, there was no windows login to run under. SharePoint will call and run the membership provider validation code under a “GenericIdentity” object user.
Now since the LDAP directory requires SSL, there are some certificates that need to be checked. The classes in System.DirectoryServices ( as opposed to System.DirectoryServices.Protocols ) automatically manage the whole certificate validation process for you. When you are logged in as a known user, it will check the user HIVE for the certificate LDAP is passing to validate, when you are a GenericIdentity, it will check the machine root for the certificate. This can present a problem since under certain circumstances it appears , that even though the certificate is in the trusted store, ASP.Net 2.0 would not examine the machine-level certificate store. The result was, the LDAP server’s certificate could not be validated and the machine would NOT make the connection. The first time sChannel logged it in the SYSTEM log (and never again till I rebooted), though in the exception object returned by the catch statement you will only get “server is not operational”
This is one area where the fix gets ugly. At the current time the only way I found around this issue was to code around it. You need to implement the LDAP connection and queries in the affected methods using the System.DirectoryServices.Protocols namespace level and you need to manually code a function to validate the certificate passed by the LDAP server to the membership/role provider. Keep in mind, the majority of the role provider calls even once you are logged in will be made with a genericidentity or as a user unknown to the server. November 07 Fun SharePoint Quirks: Deleting Master Pages This was a little annoying thing I came across recently. I had a custom master page that I pushed in with a feature. I needed to update it and of course rolling the feature back, retracting and deleting the solution did not delete the master page. So I grudgingly went in to delete it manually. Imagine my surprise when I got an error telling me it was being referenced by something and could not be deleted. I went in and checked the file associations through Site Settings --> Manage Content and Structure.
Navigate to the master pages folder, then check click the "Show related resources" button. You will find the master page is referencing itself. Thus you can NOT delete it...ever. Well not directly. turns out there is a way to remove it.
First make sure that this is the ONLY thing referencing it, then create a new folder in the master pages folder, move the master page into that folder. You can delete the folder which kills the master page. July 31 Configuring a site collection for multiple authentication providersHere is the scenario. You have a wonderful intranet site going and you’d like to share it with the outside world. You do NOT want this externally facing site using your AD, so you decide to use forms authentication for your external access. Also, you need SSL set up for the external site since you’d rather not broadcast unencrypted content across the web. 1. Configure your SQL forms authentication DB a. Determine you access methods for the forms auth DB (Integrated is the suggested way to go here) b. Create your forms Authentication database on your SQL box i. Just make sure you name it something intelligent c. The preferred way to run the following command is from a machine with Visual Studio. However, if you do not have VS you can find the exe for this call in the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 folder. i. Run the aspnet_regsql.exe command to create the forms auth table structure and SPs 1. Run down on all commands for this utility http://msdn2.microsoft.com/en-us/library/x28wfk74.aspx 2. Aspnet_regsql.exe –E -S <servername> -d <database name> -A all d. Adding the first user(s) i. Add your first user via SQL Server Management Studio by calling the following SP: declare @now datetime set @now= GETDATE() exec aspnet_Membership_CreateUser 'appName', 'userid','password','','email@somewhere.com','','',1,@now,@now,0,0,null ii. http://msdn2.microsoft.com/en-us/library/aa478949.aspx more info on these scripts e. Adding users/role via web app i. In VS.Net 05 Create a new web app ii. Add connection strings to your authentication DB within the configuration tabs of your web config 1. <system.web> <compilation debug=”false”/> <authentication = “forms” /> </system.web> <connectionStrings> <add name=”MyFormsAuthServer” connectionString=”server=servername;database=authDBName;integratedsecurity=SSPI” /> </connectionStrings>
I. From within Visual Studio à Project Menu à ASP.Net Configuration II. On the web form that pops up, use the UI to create your users and roles III. Now onto the REAL FUN! 2. Extending the forma authentication web app I. Open the MOSS Central Admin console. In Application Management, Create or Extend Web Application à Extend Existing Web Application. 1. Make sure the internal web application that you want to expose is selected 2. Set the web app name and port approrpriately Note: Take some forethought in the name and ports you use. With some planning you can use these to make life easier or make your IIS and MOSS admin consoles a mess. 3. Set allow anonymous to “yes” 4. Choose the correct Zone (probably extranet or Internet), do not choose default. 5. Click “ok” II. Now that your site is extended into the new zone, in the MOSS central admin console click the Authentication providers link in the Application security section 3. Add the forms authentication provider to web app web config i. Navigate to the web config for your extended site (created in step 2.) ii. Just after the configsections section insert the connection string for your forms authentication provider. <connectionStrings> <add name="ConnectionString" connectionString="server=serverName ;database=FormsAuthDBName;Integrated Security=SSPI;" providerName="System.Data.SqlClient" /> </connectionStrings> iii. Now scroll down to the system.web section and add the following sections: <membership defaultProvider="AcAspNetSqlMembershipProvider"> <providers> <add name="AcAspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ConnectionString" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/> </providers> </membership> <!-- role provider --> <roleManager enabled="true" defaultProvider="AcAspNetSqlRoleProvider"> <providers> <add name="AcAspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ConnectionString" applicationName="/" /> </providers> </roleManager> iv. Now repeat the same steps on the web config within your MOSS Central administration console, with one exception. The “defaultProvider” will need to be changed in the Cental Admin web config to “AspNetWindowsTokenRoleProvider.” If you do not do this, your central administration will no longer allow you to authenticate. v. If after doing this, your Central admin site crashes when you try to bring it up. 1. Check the make sure your changes are properly formed in the web config. 2. Check your connection string and make sure it is valid 3. Enable full “ugly” error messages on your central admin web application. This will give you the full text of whatever error was made in the config changes. (9 times out of ten there is something with the connection to the DB). 4. Configure forms authentication on your extended site I. You should see the zone you extended your web app listed, click on it II. Select your authentication type III. Check the “enable anonymous access” IV. Click OK 5. Set forms authentication user as secondary site administrator i. From within the SharePoint central administration console à application management section à click Site Collection administrators. ii. Make sure your site collection is selected. You will note the one on the port that was extended and assigned extranet zone is NOT listed in the listing. It is for lack of a better term, a second window into the one it was extended from. So we are making the administrator settings on the one we extended. iii. Add your forms authentication user to the secondary site administrator column. 1. This will allow this user to access the site via forms auth and add in the other forms authentication users. 2. If the site cannot resolve the forms auth username in the secondary site administrator then you have not properly modified the Central administration site web.config 6. Additional Notes I. When trying to add forms auth users to your form auth site, you will need to log into the forms auth site. The integrated site knows nothing about those users as it does not have the forms auth provider info in its web config. II. When configuring SSL for these sites, you will want to take care to look into alternate access mappings. I have seen this create a serious issue. Basically, if you set this up, then apply SSL, and suddenly your forms auth site tries to resolve to your integrate security site as soon as your users enter their credentials, you will need to work on your alternate access mappings. III. It is likely your folks using Forms auth will have issues saving and checking out documents on your portal. You will fix this with a combination of enabling client integration in the extranet zone for the FBA provider and checking the “Sign me in automatically” box on the login page. July 20 MOSS Links and Book ReferenceMOSS Link/Book Directory I am finding frequent cause to share these with lots of folks on a continuous basis. So I thought I would focus this entry on the best links I have around MOSS and some common items I have had to look up. This is not the full list I have but it is some of the best most common ones I hit. I will continually update this post to try to keep it up to date as I am adding new links and books as I hit them. Links1. Developing a MOSS 2007 VPC - Absolutely the best walkthrough I have ever seen on creating a MOSS VPC. 2. Integrating MS AJAX with MOSS - http://sharepoint.microsoft.com/blogs/mike/Lists/Posts/Post.aspx?ID=3 - http://weblogs.asp.net/jan/archive/2007/02/26/using-the-ajax-control-toolkit-in-sharepoint.aspx - Excellent walkthrough of some of the issues you will encounter with utilizing AJAX within a MOSS portal. This technology is awesome for getting your web parts to post back separately from the entire site. 3. Debugging WSS 3.0 errors - Unless you are perfect, you will run into the “An unexpected error has occurred” message from WSS 3.0 (especially if you are playing with custom web parts). Since this error usually gets you absolutely nowhere, the solution to get more info is to push in what this guys suggests. Your MOSS/WSS 3.0 site will give you standard Asp.Net error messages (note: I hope I do not have to remind every how BAD this would be to do on a production server). 4. Managing Sites and Site Collections - http://office.microsoft.com/en-us/sharepointserver/HA101577811033.aspx - Good abbreviated walkthrough on planning your site and site collection layouts 5. Mapping CMS 2002 API’s to MOSS - http://msdn2.microsoft.com/en-us/library/aa480228.aspx - For those of you who need to run your CMS 2002 into MOSS, this could prove helpful 6. MS CMS Assessment tool download 7. Sharepoint upgrade site - http://www.sharepointupgrade.com/default.aspx - Good landing page for getting information on your upgrade planning and process. 8. WSS 2.0 Prescan tool information - http://blogs.msdn.com/joelo/archive/2007/04/13/don-t-be-afraid-of-prescan-part-1.aspx - http://blogs.msdn.com/joelo/archive/2007/05/01/your-friend-prescan-what-it-does-part-2.aspx - I hit this guys site a LOT when first using PreScan.exe. he provides a lot of good detailed info on what it does and how to manage some common issues with it. 9. Developing Custom Web parts in MOSS - http://www.datasprings.com/default.aspx?tabid=775 - Very simple run through on developing a custom web part gives you a good start. 10. MOSS branding – generating a feature - http://www.heathersolomon.com/blog/articles/servermstpageforsitecollect_feature.aspx - Great chunk of info on master page branding and a path for pushing them into a feature to be easily deployed to production MOSS servers. 11. Creating BDC Entities - http://msdn2.microsoft.com/en-us/library/bb410048.aspx - From MS’ How-To series. Very cool walkthrough. Books1. Microsoft Office SharePoint Portal Server 2007 Administrators Companion - http://www.microsoft.com/MSPress/books/9537.aspx - This is the MOSS bible. I do not go near a client site without this puppy by my side or on my HD. There is just so much info in here around installing, configuring, customizing, etc MOSS, WSS 3.0. If you are going to implement MOSS this should be part of your library. 2. Inside Microsoft Windows SharePoint Services 3.0 - http://www.microsoft.com/MSPress/books/9692.aspx - Another must have book, covers a lot of stuff that your SharePoint developers will absolutely need such as using Workflow foundation, Code Access Security, CAML, and a lot more. 3. Professional Web Parts and Custom Controls - http://www.wrox.com/WileyCDA/WroxTitle/productCd-076457860X.html - Great book on web parts and custom controls which can be used in MOSS. Covers using AJAX, and some other common issues you will come across while coding your web parts. June 18 Simple SQL 2005 MOSS 2007 ADF exampleMOSS 2007 ADF (application Definition File) One of the most compelling features of MOSS is the search capability. Of those, the ability to hook into any ODBC compliant data store via the business data catalog (BDC) stands WAY out. While this is an awesome feature, the issue comes in when you try to implement it. In order to load an external data source into the BDC, you first need to define how to hook into it, how to retrieve data, how to update data, and various other information about the application. Now here is where it gets real fun. The problem with this is, while I was able to find a HUGE number of links for ADF, trying to find a simple, “ADF for idiots” type of entry was not so easy. Generally, if you can show me a simple example of something I can pick it up and run with it like an expert in no time. However such a simple example eluded me. Finally I found a cool ADF generation application. This allowed me to generate a simple ADF file for extracting data from a single data table in a SQL 2005 database which gave me the insight I needed to now create my own going forward. I will go through this sample ADF file here. To be certain this is a VERY simple example and does not go through everything you can do by any means. Hopefully, if you are new to ADF files, this will give you the boost to get you going. See the document at the end of this post for the sample ADF doc. There really are 2 key sections to focus on. 1. LobSystemInstance – this is located in the LobSystemainstances node and contains the definitions for what and how we are going to connect to the external datasource. In this sample we are hooking into a SQL Server data source. We define the server name, database name, SQL user name, and password. This sample uses SQL Auth but this can also be used for integrated or other authentication methods 2. Entity – this high level item first defines the name of the table we are accessing “dbo.TableName”. Entity has 2 other sub-sections that are critical A. Identifiers - This section defines that the primary keys is for the table we are accessing. B. Methods - The methods section defines the actions that we can use to perform specific tasks against the data store. The high level method node defines the name of the task. The Properties and Parameters sub sections further define the information on each task. a. Properties - In the first method for this sample we have 2 properties. One defines the T-SQL text used to pull the data from the data store the other defines the type of command this is (similar to how you set command type in ADO.Net code.
b. Parameters - First the individual parameter items define the direction data will be flowing - Within the parameters section we have individual TypeDescriptor subsections which will define the specific data columns and their associated data types. The sample I have listed below you can also see the additional method defined for retrieving a specific record from the data table as well as some additional details that are defined. This sample is specifically for SQL 2005 retrieval using embedded SQL. It is a good start for that purpose. Now for the sample ADF I created. <LobSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog BDCMetadata.XSD" xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog" Type="Database" Version="1.0.0.0" Name="CLIENTNAME_APPNAMELOBSystem"> <Properties> <Property Name="WildcardCharacter" Type="System.String">%</Property> </Properties> <LobSystemInstances> <LobSystemInstance Name="CLIENTNAME_APPNAMEInstance"><Properties> <Property Name="DatabaseAccessProvider" Type="System.String">SqlServer</Property> <Property Name="AuthenticationMode" Type="System.String">PassThrough</Property> <Property Name="RdbConnection Data Source" Type="System.String">SQL Server Name</Property> <Property Name="RdbConnection Initial Catalog" Type="System.String">SQL Database Name</Property> <Property Name="RdbConnection User ID" Type="System.String">sql user name</Property> <Property Name="RdbConnection Password" Type="System.String">sql password</Property> <Property Name="RdbConnection Integrated Security" Type="System.String" /> <Property Name="RdbConnection Pooling" Type="System.String">False</Property> </Properties> </LobSystemInstance> </LobSystemInstances> <Entities> <Entity EstimatedInstanceCount="0" Name="dbo.TableName"> <Identifiers> <Identifier Name="[ID]" TypeName="System.Int32" /> </Identifiers> <Methods> <Method Name="Getdbo.[TableName]"> <Properties> <Property Name="RdbCommandText" Type="System.String">Select [ID],[Name],[Description],[APP_Manufacturer],[APPOS],[AppVariant],[AppType],[AppStyle],[ColumnA],[ColumnB],[ColumnC],[ColumnD],[ColumnE],[ColumnF] From dbo.[TableName]</Property> <Property Name="RdbCommandType" Type="System.Data.CommandType">Text</Property> </Properties> <Parameters> <Parameter Direction="Return" Name="dbo.[TableName]"> <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="dbo.[TableName]DataReader" IsCollection="true"> <TypeDescriptors> <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="dbo.[TableName]DataRecord"> <TypeDescriptors> <TypeDescriptor TypeName="System.Int32" IdentifierName="[ID]" Name="ID" /> <TypeDescriptor TypeName="System.String" Name="Name" /> <TypeDescriptor TypeName="System.String" Name="Description" /> <TypeDescriptor TypeName="System.String" Name="APP_Manufacturer" /> <TypeDescriptor TypeName="System.String" Name="APPOS" /> <TypeDescriptor TypeName="System.String" Name="AppVariant" /> <TypeDescriptor TypeName="System.String" Name="AppType" /> <TypeDescriptor TypeName="System.String" Name="AppStyle" /> <TypeDescriptor TypeName="System.Int32" Name="ColumnA" /> <TypeDescriptor TypeName="System.String" Name="ColumnB" /> <TypeDescriptor TypeName="System.String" Name="ColumnC" /> <TypeDescriptor TypeName="System.String" Name="ColumnD" /> <TypeDescriptor TypeName="System.Boolean" Name="ColumnE" /> <TypeDescriptor TypeName="System.Boolean" Name="ColumnF" /> </TypeDescriptors> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name="dbo.[TableName]Finder" Type="Finder" ReturnParameterName="dbo.[TableName]" ReturnTypeDescriptorName="dbo.[TableName]DataReader" ReturnTypeDescriptorLevel="0" /></MethodInstances> </Method> <Method Name="dbo.[TableName]SpecificFinder"> <Properties> <Property Name="RdbCommandText" Type="System.String">Select [ID],[Name],[Description],[APP_Manufacturer],[APPOS],[AppVariant],[AppType],[AppStyle],[ColumnA],[ColumnB],[ColumnC],[ColumnD],[ColumnE],[ColumnF] From dbo.[TableName] Where ([ID]=@ID)</Property> <Property Name="RdbCommandType" Type="System.Data.CommandType">Text</Property> </Properties> <Parameters> <Parameter Direction="In" Name="@ID"> <TypeDescriptor TypeName="System.Int32" IdentifierName="[ID]" Name="[ID]" /> </Parameter> <Parameter Direction="Return" Name="dbo.[TableName]"> <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="dbo.[TableName]DataReader" IsCollection="true"> <TypeDescriptors> <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="dbo.[TableName]DataRecord"> <TypeDescriptors> <TypeDescriptor TypeName="System.Int32" IdentifierName="[ID]" Name="ID" /> <TypeDescriptor TypeName="System.String" Name="Name" /> <TypeDescriptor TypeName="System.String" Name="Description" /> <TypeDescriptor TypeName="System.String" Name="APP_Manufacturer" /> <TypeDescriptor TypeName="System.String" Name="APPOS" /> <TypeDescriptor TypeName="System.String" Name="AppVariant" /> <TypeDescriptor TypeName="System.String" Name="AppType" /> <TypeDescriptor TypeName="System.String" Name="AppStyle" /> <TypeDescriptor TypeName="System.Int32" Name="ColumnA" /> <TypeDescriptor TypeName="System.String" Name="ColumnB" /> <TypeDescriptor TypeName="System.String" Name="ColumnC" /> <TypeDescriptor TypeName="System.String" Name="ColumnD" /> <TypeDescriptor TypeName="System.Boolean" Name="ColumnE" /> <TypeDescriptor TypeName="System.Boolean" Name="ColumnF" /> </TypeDescriptors> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name="dbo.[TableName]SpecificFinder" Type="SpecificFinder" ReturnParameterName="dbo.[TableName]" ReturnTypeDescriptorName="dbo.[TableName]DataReader" ReturnTypeDescriptorLevel="0" /> </MethodInstances> </Method> </Methods> </Entity> </Entities> </LobSystem>
References: Contagious Curiosity Blog - http://blogs.msdn.com/socaldevgal/archive/2007/03/02/use-the-moss-bdc-get-this-adf-generator.aspx ADF References - http://msdn2.microsoft.com/en-us/library/ms145931(SQL.90).aspx Complete ADF Template - http://msdn2.microsoft.com/en-us/library/ms145313(SQL.90).aspx Minimal ADF Template - http://msdn2.microsoft.com/en-us/library/ms145232(SQL.90).aspx ADF generation Tool - http://www.bdcmetaman.com/default.aspx
May 18 The core of consultingThe Core of Consulting Contractor: a person who contracts to furnish supplies or perform work at a certain price or rate. Consultant: a person who gives professional or expert advice: a consultant on business methods. Consultants and contractors are 2 terms commonly heard in IT. Ask many IT managers what the difference is and the most frequent answer will be, a consultant costs more. Indeed, many times this is the case. But why? In Charlotte, NC you can pick up a contract employee, expert level in ASP.Net, Winforms, and SQL Server 2005. Someone who can sling as much code as the best consultant, for $90-$100 an hour. A consultant with the same level technical expertise, $150-$200/hr. So this begs the question, what is it about a consultant that should compel a company to spend that money? The core difference between a true consultant and a contractor lies not in the technical expertise, but in the end goal. A contractor’s motivation is to make their hourly rate, to perform their service, to make as much money as possible. Yes, a good contractor will perform their job efficiently, they will complete the project on time, and they will give a good pile of source code. A consultant’s goal is different. Yes, a consultant like everyone else wants to make money. However, a consultants role is filled by removing their clients need for them. A consultant’s drive is to make their clients business better than it was when they began. To not only sling code, but to draw on their expertise, and experience to empower their clients to stand on their own, to do their jobs better. The value to the client lies in this motivation and a consultant who keeps this in the front of his mind will have no lack of clients. As consultants we should always be asking ourselves, “What value am I bringing my client?”, “How am I making their business better?”. Any consultant who has been on their job more than a few months will have a few horror stories to tell that they have heard from their clients. Stories of consultants who have let go of the core values of consulting and abused the trust their clients put in them. Personally, I have paid the penance for many of these types of consultants at various clients. I have come into clients with all eyes on me waiting for me to rip them off. I have felt the mistrust, had my value called into question. I have been sucked into many a political war within my clients organization. It can be a tough field, and it can wear you down. The key to it all is to never lose site of the core values, the guidelines that should lead any consultant. HONESTY: No client will ever see the value in your service unless they can trust you. When you come into a client site with your higher rates, your certifications, your glowing resume, that will not necessarily get you trust. Trust is earned and being deceptive, secretive, anything other than utterly transparent and up front will guarantee that you will not win the trust of your client. Without trust, your entire value proposition is out the window and your rates are unjustified. Also, until consulting is done by robots, remember you will absolutely run into situations when you will not know an answer. Do not be afraid to say “I don’t know.”. Many consultants think they need to always have an answer. There are few more reputation destroying situations then when a consultant produces a rectally generated answer and is called out by a client on it. Such a situation can irreparably damage a client relationship and an entire firm’s reputation. While you can easily remove your ignorance on a topic with a book, web search, or training, you cannot so easily rebuilt your reputation, so guard it very carefully. CUSTOMER FOCUS: This is a buzzword thrown around every board room in the world. So what does it mean? Looking back at the consultant’s motivation, customer focus means you are their champion. You are keeping them in mind while you are performing your contracted tasks. You are also keeping your eyes and ears open. You are looking for ways they can improve things. Areas you know you can help them in. You are identifying bottlenecks, inefficiencies, and needs they may not even realize they have. You are also looking for dangers. You are the expert, you need to act like it. This does not mean you are an eager little sales monster running around trying to squeeze anything you can from your clients like juice from grapes. Remember though what you end up with is crushed grapes and you will not get any more business from such a client. It is a fine line that is easily crossed. Before you run to a client about any needs you have identified in their organization stop and say “How would filling this need benefit my client?” and consider this along with your own cost. A client should have no doubt that you are in their corner. You need to be engaged with your client. Be openly interested in their business. How they do things, WHAT they do. Personally, I have made it a point to request tours of every manufacturing facility for any business I have work with. To engage with project sponsors on their business focus for Insurance, health care, amusement parks, banking, and many other verticals, on my own time. I have seen clients describe with pride what their company does and gotten a solid knowledge of their value proposition to THEIR clients. Once you have that knowledge you will know how to help them not JUST in your project but as an entire enterprise. You can relate your suggestions to that and you can provide value to those suggestions in terms that are meaningful to them. You do this and you not have to worry about sales. EGO-LESSS EMPATHY: This is closely related to customer focus but is so critical that it bears separation. First thing, the engagement is not about you. As a consultant, you will find yourselves periodically in difficult situations within a client. You will end up in situations as I mentioned earlier where you will pay for mistakes or fraud that other consulting shops have done to your client. You will have your integrity and competency challenged. An awesome way to win a client over is to weather this type of situation like a rock. This can be difficult but if you can keep your ego in check, and empathize with your client a bit. Your project sponsor may have taken quite a beating, had their own career threatened by going out on a limb with another firm, or they may be doing that with your firm. Get an understanding to what other shops have done to them. Learn some of the background behind your firms involvement. Frequently you will glean some information of the behind the scenes discussions that brought you onsite. You may even learn some items about your client’s specific culture that prevent you from repeating other firms’ mistakes. Take the beating, and stand firm on your core guidelines and you will win most clients over and prove your value proposition to them. PASSION: Most good consultants I have come across have a sincere passion for what they do. They have a passion for helping manage, architect, develop, test, and deploy their solutions. They have a passion for pushing a positive impact into their clients business. Much as a little league coach has a passion for coaching their team members into better players, a consultant takes pride and sincerely enjoys the positive impact they have on their clients business. A client can feel passion, they are drawn to it. They feed off of it and it energizes them. It gives them an almost unexplained comfort and excitement for the projects and encourages them to re-engage with a firm over and over. It can be unstoppable and get you through some really challenging projects. It can also help insulate you from burn-out which can be a real career killer in the consulting business. This does not mean you hang from light fixtures, or work through a 24 shift smiling and whistling (that can actually get you killed on some client sites). But it means you keep your eyes on the prize, and appreciate the positive impact you will be bringing to the client. ANY technical skill can be taught, passion for the field can’t. INTEGRITY: This rides hand in hand with honesty and is critical. A firm’s reputation can be built solidly on a foundation of integrity and honesty, and it can also be completely destroyed by a lack of it. To give an example, while on a client site, I was placed in a cube directly across from a conference room utilized by the board and very high level management on a regular basis. Unfortunately, they frequently left the door open and when they didn’t the walls were so thin you could easily hear them. Shortly after being put in this cube, the board of directors went into the room and began talking about the consulting firms they were considering for a number of huge projects. Obviously they were discussing my firm and our competitor. It would have been easy to sit there, and listen to the discussion. Maybe help my company grab a competitive edge going forward. After all, they are the ones who put me in the cube. I got up, went to our project sponsor and informed him of the part of the discussion I had heard and advised him to move me to another cube where I would not be picking up business confidential information out of that room. Shortly afterwards, their maintenance crews replace the walls and doors and made that room completely sound proof. We won more than a years consulting contracts with them for our firms integrity. Integrity sells, it breeds client trust, and it is a critical component for any consultant.
So, now that we have defined the core characteristics of a good consultant, let’s take a good look at some key points to keep in mind during any client engagement. It is critical that a consultant understands their role in the universe. Granted, depending on the size of your shop, the lines between roles may blur a bit but in general these following key points should still hold true. We’ll tackle what can be the most difficult balancing act to being a consultant first. A consultant is not a salesperson There is many a consulting manager who may take offense at this statement. However, I think it is critical a consultant understand, like the object orientated technology they work with, the people in their organization all fill a role. These roles all have different focus points and goals. While overall they all exist to serve their consulting shop, the ways in which they do so, differ. A sales staff is paid by commission for a reason, they are sales focused. They are driven to reach their sales goals, to get enough business to keep the consultants in their organization fully utilized. They attend sales and partner conferences, they look to ways to build alliances with other companies to drive sales higher. Hopefully, they too try to build a good chunk of their own value on meeting customer needs, but they also need to be focused on making the dime, for any reason because someone in the organization needs to have that focus. This is why their compensation is based on commission their sales numbers or their performance metric, and that is how they are evaluated by the organization. Don’t get me wrong, a consultant does not walk around the work blind to the sales cycle. They frequently partake in pre-sales calls, product demos, and in identifying needs within the client; they are identifying sales opportunities for their organization. If a consultant holds to the core values, then they will greatly aid the sales team, they will drive repeat business and help shorten the sales cycle. They will learn to present demos and pre-sales presentations in ways that demonstrate the value of what is being sold in terms the client can understand. The will be their sales staffs best friend. However, as a consultant you will not set rates, you will not make deals. Each role is a cog in the machine that makes up their consulting company. As mentioned before, as a consultant, you goal is to focus on your customers, to empower them to do their business better, to at least in terms of the current project, remove their need for you. It is a very fine line sometimes that differentiates you from the sales team, but it is a separation that must be made. Amongst the horror stories I have heard from clients is the consultant that runs around trying to squeeze every last dime out if them regardless of the actual value that it brings to the client. There are few quicker ways to hose a client’s trust in you than to convince them, through your actions, all you really care about is shaking them down for a dime. Without trust you lose the value proposition a consultant brings, and you lose the validation for those bill rates.
Do not forget about the primary customer As a consultant, working for a consulting shop, it is critical to realize that you have one primary customer. That is your employer. Your continued employment is dependent on the company name printed in your paycheck. It is important to look at your employer in many ways the same you would look at your other clients. You need to be honest with them, carefully train and build your skill set to provide the maximum value to their client base. You need to identify ways you can help to improve the ways they do business, and step up and “volunteer” to do this, keeping in mind that while your employer may not pay the bill rates, they do pay your paycheck so your volunteer work, is not really volunteer work. Not only is this good for healthy career growth but it is an awesome way to internally work on building your consulting skills. It is a poor consultant, and eventually an unemployed one, who thinks they can exercise a clear unfettered focus on the clients and completely ignore their employer. Be honest with them, deal with your employer with integrity, share the passion that you have for your career, sometimes it is infectious. Deal with your employer and co-workers with the same ego-less empathy you extend to your clients. Unless you are an independent you are not the only person working hard, stressing out, etc. Keep that in mind and do not ever overinflate your importance. When it comes to your employer, you need to be transparent in your communication with them. They cannot and will not fix anything they do not know about. Your employer should be no more surprised than you are about the direction a project takes. You do not need to feed every little detail to them, but you should be giving your direct manager enough information about an engagement that they are well aware of at least the general direction of the project. In addition, if you put in your notice, your employer should not be too surprised by this (unless they are denial). They should not be unaware of any issue that specifically leads to your resignation. This is not always an easy item and occasionally there can be times when your specific client needs conflict with the company you work for. This is another area that transparency with your employer becomes critical. If you disagree with a policy or a specific situation that you feel puts your commitment to your employer and your clients in conflict, you need to address that with your employer as soon as possible (and keep the ego in check). It may simply be a misunderstanding, or there may be a very good reason for a policy that creates the conflict. Either way, it helps your employer to evaluate their policy when they know where it conflicts and it assists you in dealing with your clients when you know the reasoning behind it. The point is, you will have serious issues maintaining a healthy relationship with any of your clients if your relationship with your employer is in a bad state. No matter how hard you try to avoid it, the vast majority of times it will in some way impact your work with the client. If there is a major philosophical rift between your beliefs in how to do your job and your employers, it may be time to consider a new position (and re-evaluate how what questions you ask during your interview process). You cannot battle your employer and serve their clients appropriately. You also cannot just ignore you employer and operate autonomously. You will generate client expectations that vary greatly from what your employer will meet. In the end you will be setting your client and your employer up for a bad experience and that is simply unacceptable, and unfair to both of them. Manage your Value The good old “V” word. To a consultant this is what it is all about. Keep in mind, your rates are going to be significantly higher than a contractor. It is up to you, not your employer, to prove that value. Certainly, an employer can enhance your value with solid laptops, labs, training, a solid set of base classes, standards, email technical support, IM, etc. but these are just tools. It is the consultant who turns the tools into value, adding them to his/her own value. You should honestly look at yourself in the mirror at regular intervals and ask yourself, would YOU pay your rates for the work you are doing? Would YOU hire your firm for that second engagement? If your client turned to you tomorrow and asked you to justify your rates from his point of view, could you? It is absolutely critical you help your employer sell YOU by making yourself more valuable to them. Talk to the sales staff, the consulting managers, the company president about the sales pipeline, this will give a good indication to what you will be working on in the next few months. Talk to your clients about where they are looking in 5, 10, 15 years. Identify the key technologies, skills, etc that will shape the future of your career. As an example, in 2001-2003 when the golden era of custom built ASP.Net based web applications was coming to an end, many consultants I worked with tried to rage against the death of that area of business. They loved architecting, and coding these systems. They spat at the notion of learning this new set of MS based products coming out in the world. SharePoint, BizTalk, Commerce Server. They refused to be a “Product” guy. I had a chat with my consulting manager and found SharePoint was in high demand, A checked my ego and began to learn it in earnest. In 2004-2005 we got bought out by a large firm who laid off more than 50% of our staff. None of the SharePoint or BizTalk folks were in that group. Not only that, we were the only people who qualified consistently for quarterly utilization bonuses. Not one of us was under 90% utilized and many of us were 100+% utilized. There were actually internal tug of wars over SharePoint and BizTalk folks because so few had adapted to the skill set. Those fights continue today in many organizations. It is not about what you want it is about what the clients want. A consultant constantly realigns their technical skills to meet the needs of their client base. Sometimes this means coming out of your comfort zone and learning new technologies, maybe moving away from technologies that you really liked. If I would have even tried to guess the impact BizTalk Server and SharePoint would have on the market 5 years ago, I never would have seen demand rise as fast as it has. As I stated before, it is not about you, it is about the clients and what they want or more importantly (since sometimes they do not know what they want), what they need to maximize their business. Maintain Professional distance While it is important to foster a healthy relationship with your clients, always be careful to maintain a certain professional distance with your clients. On the surface, it may sound like good customer service and focus to get as personal as possible with your clients. However, this is an area that can turn ugly quickly. It can be tough enough to maintain a decent professional relationship sometimes, when you throw in the emotional ramifications of a personal relationship, you can easily end up over your head, or in litigation. This does not mean you walk around calling you client “sir” or “maam”, or Mr./Mrs. Smith. Be authentic and personable but be careful how much of your guard you let down. You do not ever want to completely let it down. Remember your purpose there and remember who you work for. I was on a project where a senior architect with my company came within a breath of a physical altercation with a clients architect because they he did not way too personal with the client. Remember, at the end of the day, it is still a job, it is business, and you should be careful to keep that in mind. Be careful to try to avoid a situation where you delve into the conversational danger zones with clients. The biggest dangers are religion and politics. Keep in mind you are there representing your company, your endorsement of a particular political or religious affiliation could easily be tied to your company’s endorsing the same. Some clients do take it to this level regardless of how delicate you attempt to be, just be very careful. Another key point to remember while maintaining this distance, do NOT under any circumstances bring any issue(s) you may have with your employer into a client engagement. It is none of their business and really is a violation of the trust your employer puts in you to do so. In one of my previous companies, we had a team whose members were extremely unhappy with our company. They went on a multi-million dollar project we fought for months to win, and openly bashed our company. Some even went so far as to discuss interviews they were going on. It only took 2 months for the client to decide they no longer wanted to pay invoices and kick all our staff out the front door. If you do not have anything positive to say about your own company then do not discuss it. I would also suggest you follow the guidelines in the section on your primary customer (your employer). Also, when talking about anything positive about our company avoid specific figures, details on benefits, etc. I have had clients try to glean this information in the hopes of using it to negotiate rates on a future engagement. This balance can differ by client, by consultant, and even on different projects within the same client. It is a very grey area and really is something you need to evaluate as you move through an engagement. Should you run into a situation where you are concerned about the distance you have maintained, discuss with your peers or immediate manager for guidance. Avoid Negative Viral Behavior and Discussion Negative viral behavior is the term I use to describe behavior that tends to spread negative feelings and behavior throughout an organization. This includes negative discussion or slandering the client, client staff, project progress, your own employer, one of your co-workers, etc. or just generally being miserable consistently on a project. This type of behavior has a way of spreading like a virus across a company. It will severely impact morale, and frequently the amount and quality of work being done. It can cast a shadow over the entire project while it is being done and after you are gone. It is important to remember as the “outsider” there will be a tendency for negative feelings for a project to end up being associated with you and your company. So if you were the consultant on the “project from hell”, that could negatively impact the clients perception of you and your entire company. I have seen this happen on projects that actually came in on-time, under budget, and exceeding expectations on scope. That negative shadow can leave a scar on the client’s staff that they will remember and hold against you and your company for a long time. The good thing about this type of behavior comes when you walk into a situation like this. This is because the opposite behavior can also be viral (although not always to the extent that negative behavior can). At the very least, it can result in your own reputation being elevated. A positive person in a sea of discontent is a refreshing break for those sailing that particular sea. This does not mean you walk around whistling gleefully unaware of anything negative on the project. That can make a client think you just do not care or are completely oblivious to the situation. It means you keep your professional edge. When folks start down a negative road you try to steer them towards the goals on the project. You try to keep them focused on the task at hand. Make sure you highlight the successes on the project and show a solid resolve to hammer at the obstacles in your path. I was on a project on the east coast of the US that summed up the worst case scenario for any project that I had or have ever been on. Our project sponsor had a terminal illness and was generally in some level of pain most days (he had other things than the project in his head). We were called in to implement a project that has been scoped by another consulting company who happened to interview about 25% of the stakeholders and identified even a smaller percentage of the actual functional requirements to make the project work. The clients project manager, had a habit of pulling you into his office to tell you at length how much he hated his job and wanted to leave, on top of that he loved Linux, Java, etc and hated anything Microsoft, being I worked for a Gold Certified Partner, I was a step above the devil to him. It took less than a week for us to identify these issues. We spent 5 weeks doing a new scoping effort, all the time keeping a positive, business mentality. We tackled the scoping effort, probably put 10 miles a day on our shoes walking the building meeting with users, stakeholders, etc. We put out a new estimate that pushed the estimated cost of the project to 5 times the initial estimate from the other consulting company. We then got to present it to the board. While the board decided they could not afford the final real estimate of the project, they revealed to us that we had concluded the scoping effort in 1.4 the time the original company did. In addition, we had actually raised moral throughout the office with our unflinching can-do attitudes and our determined approach to completing the project. It helped inspire their staff to work harder and one had even called us “team Teflon“ for the way the stress seemed to fall right off us. To be sure, every member of our team was extremely stressed during that project. It was probably one of the hardest any of us had to ever do and more than once we found we had to actively work to bite our tongues and keep going. The point is, by not delving into the negative feelings we were surrounded by, we were able to finish a very difficult project, and bring it to what probably was the best outcome we could have hoped for. Analyze, Learn, and Recover from Failures Managers do not always want to admit this, but as long as consultants are still human beings, and their clients are human beings, there will always be mistakes and failures. These can come in many areas for many reasons, an incorrectly scoped project, bad estimates, unforeseen technical difficulties, staff turnover, or just plain old-fashioned mistakes. There is one very important thing to remember about a failure, it is a (hopefully rare) opportunity. First, it provides an opportunity to prove to a client how good your customer service is. The true character of a consultant and company is exposed in how it deals with its failures. Recover from a failure with your client and make up for it, and you will find some serious customer loyalty. Ironically, it gives a client a high level of confidence in a consultant/company, when they know that even when they mess up, they will still be there to serve them and drive an engagement to a successful conclusion, regardless of what happens. Generally a client will tolerate some failures and mistakes, as long as they are not an everyday occurrence. In the event a project completely fails as a result of some failure, then you can still salvage a client relationship on how you deal with your failure. Personally, I have gotten a tremendous amount of respect from client from simply stepping up and claiming my mistakes, then dealing with them. Nobody likes folks who insist on pushing the buck around, and wasting time rather than fixing the issue. Be honest, be direct, be effective and fix it. Another important opportunity is provided in analyzing a failure. Determine why it failed, how to avoid such a failure in the future, and disseminate this information around your organization. The old adage holds true, you will learn more from your failures than you will successes. Just do not make them a habit. Cover Your “Assets” There are much more crude ways to put this, but it is all about keeping an auditable set of footprints in what you do. Hopefully, depending on what vertical you are working in, the need to review this information will not be an everyday occurrence. However, when you do need it, having a track of what you have said and done, and what others have said and authorized you to do will save you a lot of pain and misery. In the world we live in, if you are consulting you will come into a situation where this will save you. For various reasons, office politics, faulty memories, scape-goating, etc a perfectly clear and simple undocumented hallway discussion/decision can end up costing you a lot. You do not want to get into a he said/she said situation with a client. No matter who wins the argument, you lose. Conduct business discussions/decisions in a manner that provides a clear record of what is being said and done. A few critical guidelines for this: · Do not conduct critical decision making meetings one on one verbally with no backup. o If this is not possible, write up a summary of the discussion and decisions made (and who made them) and have the other individual sign that summary before moving forward on any of those decisions. · Any critical work summary, or detail or authorization should be documented and preferably signed. o For some documents you may not require a signature, but having the client email it to you may help provide you at least a minimal safety net. · Save all project emails o I will create a folder for any and all emails on a project. I will save them all for the duration of the project, and then archive them off at the conclusion of the project and save the archive. o You never know when a seemingly simple and meaningless email to/from a client will end up being the one that saves you. · Strictly adhere to your company’s guidelines/standard on this area, especially if they are more stringent than your own. o While your own standards will evolve based on your personal project experience, your company’s will evolve based on a summary of all their project experience. If they are more stringent, there usually is a reason. Be a good idea to discuss it with your manager, to get a clear idea as to why and help expand your understanding. · If you are being asked to go into an area of discussion or decision that in any way concerns you as to legality/liability, STOP. Consult a manager or legal advisor and find out the liability/legality. Do not think you are alright, know you are.
Another good thing about forcing a documentation trail is that by human nature, when someone is forced to write it down and sign for something, they will look it over more, give it more thought, double check their decisions. In short, you may catch a severe issue before it gets to become a problem. This is especially true for technical specifications, there are many times I have verbally discussed a proposed change to an architecture and when I got to documenting it, an issue with the change becomes clear. Also, unless you have a photographic memory, it is likely you will forget something discussed. I make a habit of transcribing all my notes as well as items in my head from a meeting into a one note notebook. While I may lose a paper notepad, or forget ideas, issues, reasoning at the time, etc, I can always review my One Note notebooks. This has come in handy on many engagements. “I don’t know” This can be the toughest thing for a consultant to say. As a consultant you may have the notion that you should know the answer to every question. This is an unreasonable and unrealistic expectation. No matter how talented you are you will end up in a situation where you are asked a question or series of questions you do not know the answer(s) to. This is even more likely for a technical consultant because we frequently work with newer, poorly documented technologies, with comparatively little experience to other older technologies. The fact that they are new means that there will be areas of that product and its functionality you have never used. There may be ways a client wants to use it that you simply have never even considered. It will happen over and over throughout your career no matter how well you prepare for it. In this type of situation, the value of a consultant is found first of all in his/her ability to admit they do not know instead of blindly making up answers that sound good, or probable. As a consultant you likely have access to material your client does not AND the bandwidth to get answers to questions you cannot answer. Also remember your value and be confident in it. You are there for your technical capability but also more importantly because of your field experience. Feel confident in telling them you do not know the answer to their question, but for any of these areas, take notes and make a commitment to your client that you will get them a solid answer within a specific time frame.
Be a Consulting Chameleon The old saying goes “You never get a second chance to make a first impression”, and to an extent this holds true. Before going onsite with a client or engaging in a face to face meeting, find out what their culture is like, and especially their dress. Your sales force will always dress a specific way, as will your corporate executives. It is appropriate to their roles. However, as a consultant you will work with, amongst the client and their staff. While it may seem petty, the impression you leave with the client from your appearance can be a hindrance to building a good working environment and establishing your value with the clients team. I am sure very few consultants who have had their jobs more than 2 weeks would wear sneakers with holes, and a beer T-Shirt to a client site or meeting. But somewhere in between that extreme and a Tuxedo you will need to pick a look that allows you to work comfortably with the client. You want to be sure you do not dress under them but you also do not want to dress over them. Either mistake can cost you in negative client perception. Dressing beneath them can give them the impression you don’t really take them seriously, or it can diminish their perception of your value. Likewise dressing well over them, first of all makes you stand-out. It may make them think you consider yourself above them, superior, or elitist. Either way it can make it difficult to intermingle and work with the client as a team. From talking with clients at the end of an engagement, I have found a good point to be on this, is slightly dressed over the client. This gives them the impression that you are first of all taking them seriously, and second of all, that you are “one of them”. In addition to dress, learn the culture and work with it. Every office has a culture and while they can share similarities, every one is somewhat unique. There are dynamics to work out, politics to learn, that in some cases can make or break a project. As an example, on a project I was on, the client team had an architect that was extremely picky on the ways thing needed to be done. On top of this he was slightly threatened by outsiders being brought in. As I came into the project, I found he had not been invited to a lot of meetings, not because of any controversy or any issues with him, but because logically, what we had been discussing did not directly impact him at the time. As a result, he found a way to slam almost every facet of the project architecture usually over very minor things. We started inviting him into the discussions, allowing him input to the meetings. For almost all the meetings, he did not say a word, he would listen and nod. However, we found after this, he had no issues with the project architecture. We also found that pretty much throughout the enterprise the client staff was already doing this for the same reasons. You will need to come in with a bit of humility, ask questions, learn the culture as fast as possible, and adjust your approach to use that culture to maximize your effectiveness. You will also find the client staff will generally appreciate this and warm up to your presence. Expect to get burned, don’t get jaded This is one of the most frustrating parts of consulting, at least for this author. No matter how good you are in the core consulting skills, and no matter how well you hold to the guidelines you will get customers who take advantage of your focus on them. It is part of the business and a risk you take with consulting. Sometimes it is just because they are clueless, sometimes it is deliberate. Either way, it does not feel good and it is sometimes very costly. This can be the client who uses you during a sales cycle to pull free work from you, and walks away without purchasing any services, the client who gets services and then skimps out on paying, the client who manipulates the document set to ensure a hole for scope creep, or who deliberately tanks a project for political reasons. The key here is to analyze the items that allowed a client to burn you. Once you get these together, determine what reasonable steps there are to mitigate the risk of this in the future and measure that to what level of customer service you are willing to sacrifice to implement those changes. It is all about what amount of risk you are willing to accept. Going out on a limb for a client, accepting some risk to meet their needs can provide huge payoffs. Generally, the bigger the risk the bigger the payoff. The inverse is also true about risk. The bigger the risk, the bigger the potential loss. It is a balance that each consulting shop must make for themselves. Remember though that the vast majority of clients are not going to fall into this category and it is acceptable to make some sacrifices and take extra risk for clients who have showed themselves trustworthy. One way to show a client how much you appreciate their business (especially repeat business) is to intelligently loosen some of the restrictions and accept additional risk in your dealing with them. Good customer service is truly lacking in many consulting shops and many times this is why. Good customer service costs money, it involves a level of trust and risk and any risk carries the potential for loss. The good clients I have dealt with though, recognize when you go out on a limb for them and they remember that. It is one of the potential differentiating factors that add to your value. May 09 An Idiot's guide to MOSS Custom Webpart AJAX Issues All I have to say is, with the huge amount of info I found on blogs for using the MS AJAX 1.0 controls within a MOSS 2007 Web part, I found the biggest technical issues I ran into instituting this was retarded little "details" that i simply overlooked while digging into deep technical issues. So let's assume you have your web part coded, You may have used a blog or perhaps your own little ASP.Net 2.0 Ajax enabled web site as a guide. You bring it up and whammo it is not working. I had issues in 2 different areas as I describe below. Anyone else got any other pointers, PLEASE post them in a comment to this blog. Also, if you have not done so, read the references on the bottom of this entry. I found these helpful in getting a good base understanding of what I needed to do in getting things working. So without further ado:
1. Web part seems to work except the AJAX calls are not being made, the entire page is being submitted.
a. Did you include your script manager object?
- No script manager object no ajax calls.
b. Did you actually add you controls via the "ContentTemplateContainer.Controls.Add" function?
- You can google the namespace to figure this out but you will need to add your controls via this function
c. Did you correctly setup your async triggers?
d. and....Have you actually made the changes to the Web.Config that will enable AJAX?
- Remember there is a difference between an ASP.Net site and an AJAX enabled ASP.Net site, it is in the web.config declarations in
there. Without them the app will have no idea what you want it to do in terms of AJAX.
2. AJAX calls work fine the first time, then, after that nothing works in terms of postback(AJAX or otherwise)
- Did you put in "EnsureUpdatePanelFixups" type function and actually execute it? (See Mike Ammerlans blog for sample)
- Double check the order which you are initializing all your controls. It is very easy to call put your code in the wrong overriden
function and have it get called in correct order on a first load and incorrect order on a post back as the serverside code cycles
through the event handlers.
3. You get the dreaded "An unexpected error has occured" message with no further messages or logs to help you figure out what has
gone wrong. You can modify the web config, to get MOSS to display the full "ugly" ASP.Net error messages. This displayed an error for
me that would have NEVER found without it. To do this:
<SafeMode MaxControls=“200“ CallStack=“true“… <customErrors mode=“Off“/> a BIG thanks goes out to the thekid.me.uk blog for this information (see link below to check them out) . BTW, it is best you do this on a dev setup if at all possible. Remember, these error message will be shown to ALL users. Not exactly the best situation for a production setup. If you have to do this on a production setup, be sure to change your config file back when you are done.
References:
Mike Ammerlaan's Blog http://sharepoint.microsoft.com/blogs/mike/Lists/Posts/Post.aspx?ID=3
Jan Tielan's Blog http://weblogs.asp.net/jan/archive/2007/02/26/using-the-ajax-control-toolkit-in-sharepoint.aspx
thekid.me.uk blog: http://blog.thekid.me.uk/archive/2007/02/15/a-solution-to-quot-an-unexpected-error-has-occurred-quot-in-wss-v3.aspx
April 30 MOSS 2007 Pain, interests, etc To date, I have been posting as much as possible in here as I am learning, hitting walls, finding gaps in online documentation around MOSS and other technology areas. I am hoping that this is at least helpful to someone out there. To that end, i would like to solicit any ideas from anyone who may wander onto hear with a pain, or interest specifically with MOSS 2007, AJAX, etc. Feel free to challenge me, I have enjoyed a lot of the research efforts I have done to date, and I would be very interested in some of the things some of my colleagues are encountering out in the wild. Depending on how many requests I get I may not get to all of them, but I will attempt to address any that seem to come up frequently first.
Just respond to this posting with your ideas. I look forward to hearing any. Custom Web Part Development UI Options So I recently got on a project that involved me finally putting some of my theoretical knowledge of custom web part development around MOSS into practice. For those of you who know nothing about these. Basically, in oversimplified terms, a custom web part is a specialized server control. If you have not coded server controls, this is not much more difficult than normal ASP.Net 2.0 coding except take out the nice HTML/Design view UI designed and go back 5 years to classic ASP coding. So if you like doing nitty gritty HTML generation, well you are about to trip into heaven. For the rest of us, well what can I say...this is a serious deficiency on MS' part.
Not to worry, if you have a client who is willing to accept it there are options. You could utilize the "Son of Smart Part" which is a web part that serves as a container for standard ascx controls. In SPS03 I had used its predecessor and another called the User Control Container. The issue with some of these is they do not always include the source code so you have to trust the author. It is used quite widely though so I would hope if there is something devious in there, it would be noticed by now, but if you have a client who has strict HIPPA, DOD, or other compliance issues and you cannot afford a 3rd party control from an untrusted source (at least not trusted by your own organization), you could roll your own. Given the time you will save not continuously rewriting your Web part UI's will be significant, it would be worth your effort to invest some time.
Another option...amongst the web parts out of the box with MOSS you got you standard page viewer. You could host your "web part" as a standalone ASP.Net 2.0 web site and embed it in a web page viewer part. This is another option I have used, especially when specific requirement of the application or the underlying technology require it.
To be sure these are workarounds but they do work and work very well. If you do decide to roll your own web part and are willing to invest in slogging it through generating your own UI, then I have a couple pointers for you. First of all, build some helper classes to generate your HTML. My first swipe through this, I got a table helper, that generates table, tr, td, etc tags for me. It provides a simple way to code the UI and significantly shortens the source code. I also have helpers to generate the ASP.Net controls (since I actually need my web part to say more than "Hello World".) I am in the process of pushing the MS ASP.Net 2.0 AJAX controls out into my web parts, as soon as I complete that I will let Y'all know how it goes but so far I am impressed with those as well.
Now one other option I wish I could say I came up with, but I didn't and it was just plain cool. I had done something like it way back when XML first came out in the classic ASP age. You can create web services, or BL classes to generate dynamic sections of your UI data in a standard XML format then transform it with some XSL files. Now the one I saw was so generalized that you could feed just about any data through it you'd like and just plug it into different xsl files through the Web part properties (If you use web services you can also set these in that property pane within MOSS itself).
Hopefully, this gives you enough information to go forth and be dangerous. I would like to thank Brian Sok for the assistance and brain dump in getting me to the point where I can somewhat intelligently develop these things.
One other note, to be fair to MS, word is there is some type of update coming for the visual studio 2005 to finally bring these into the IDE and allow a clean and less insane way to generate UI's. I would have to say I am EAGERLY awaiting anything in that area, and have been so since I coded my first SPS03 web part.
March 23 Don't forget about the double hop I have to admit, I was 100% embarrassed by this it happened. It led to a full week in hell for me and the sad part is it was not the first time that it happened. So, let me explain. I had coded a nice little ASP.Net app that took a users credentials (via integrated security) and contacted an Exchange 2007 Web Service to grab and display a real quick summary of the users inbox and calendar (after all we do not want to reinvent OWA). This was to be loaded into a SharePoint portal Server 2003 intranet portal on a small little web part running in the window. What's more it was loaded via an AJAX call from the client. So now I hope and pray that someone reading this is not seeing it blatantly obvious as to what was wrong with this plan. To give you a hint, they did not have Kerberos set up on this network.
So for those of you who like me forgot something which not too long ago was a huge issue for me that always stood in the front of my mind. It is all about NTLM and the tokens generated between the client and server and once upon a time a long time ago (well long in IT terms anyway) I ran into this issue head on. That was a while ago and i have had a long time since I needed to actually impersonate a user beyond the standard client/server setup.
The "issue" with NTLM is I assume completely by design. When a client authenticates to the server a token is generated for that authentication which is valid only between those 2 physical computers. I mean imagine the havoc you could wreak if you were to slip an integrated auth web site onto a corporate web server (especially since you can install it easily with an msi) or if you quietly slipped some code into a base class. Once you had hat users auth, you could now be them for calls all across an enterprise. You could grab all their email, trash corporate resources, steal files, and everything you do you would do as them. A decent hacker could probably come up with a million other scenarios. I imagine admins everywhere would be forever afraid to log in.
Anyways what kind of characteristics will you see when you are in this situation? Well for one you will be able to open the site on the server and log in as whoever just fine. Then someone hits it remotely and you web service call returns a 401.1 authentication error.
(While I have i tin my head, here is a good way to diagnose those 401 issues: http://blogs.msdn.com/david.wang/archive/2005/07/14/HOWTO_Diagnose_IIS_401_Access_Denied.aspx)
So what are the ways around it? Well first of all delegation using Kerberos auth there are some restrictions to it though and you will need to read up on it and see if it is a fit for your situation. In our case, we moved the ASP.Net app to a special port on the exchange server itself. That way out communication became between 2 physical machines and NTLM was just fine. So should you fall into this conundrum yourself here is an awesome links for you:
The "Double Hop" issue
|
|
|