Friday, October 31, 2008

Best Practices for Writing HTML in Web Parts?

Something that's as puzzling as the Cadbury secret (and we all know that us programmers figured that out long ago) is just what's the best way to write out HTML in Web Parts? So call me masochistic but I write Web Parts with code. Yes, it's ugly. Yes, it's painful. Yes, you could use something cool like SmartPart or load the controls yourself (but that brings on a host of other issues like Code Access Security so we won't go into that).

For those of us that hold true to the "old fashioned" way, what's the best way to write all that code out? Consider these two approaches that writes out a label and control in a row for a form:

private void RenderRow(HtmlTextWriter output, Label label, WebControl control)

{

output.Write("");

label.RenderControl(output);

output.Write("");

control.RenderControl(output);

output.Write("");

}



private void RenderRow(HtmlTextWriter output, Label label, WebControl control)

{

output.RenderBeginTag("tr");

output.RenderBeginTag("td");

output.AddAttribute("class", "ms-formlabel");

output.AddAttribute("valign", "top");

output.AddAttribute("nowrap", "true");

label.RenderControl(output);

output.RenderEndTag();

output.RenderBeginTag("td");

output.AddAttribute("class", "ms-formbody");

control.RenderControl(output);

output.RenderEndTag();

output.RenderEndTag();

}



Both output exactly the same HTML. Does it matter? The first approach is less lines but is it any more (or less) readable? Or maybe everything should be built up in a StringBuilder class and slammed out to the HtmlTextWriter? Or is it simply whatever is readable or maintainable works? Looking for your thoughts, ideas, suggestions, rants, assorted concealed lizards of any kind.

Friday, October 10, 2008

Giving Background Dynamically for Cells in ASP.Net Report Control

Right Click in the cell and click Properties. Click on the Background color in the Property box and click expression in the dropdown box for selecting the background color.

=iif(Parameters!oTotal.Value = Fields!RowCount.Value ,"YellowGreen","White")

If Row Count and Total are equal, Background color would be YellowGreen, else White.

Giving Visibility True / False for a Report Control Row or Column

Right click in the field(cell) and click expression and add Expression as
=iif(Parameters!oTotal.Value = Fields!RowCount.Value ,False,True)


Right click in the cell again and click Properties
Click visibility tab and add expression as
=iif(Max(Fields!RowCount.Value)=5,Fields!ActualSales.Value+Fields!TOTALSales.Value,0)

Cross-forest deployments of SharePoint Portal SPS 2003

SharePoint Portal Server 2003 Cross forest deployment scenarios

One of the deployment scenarios that we were pretty naive about in SPS 2003 was the deployment of SPS in the enterprise with multiple forests. Part of why that happened was because we miscalculated how we thought AD deployments would happen.

At the beginning of the O11 planning cycle (spring 2001), we asked the AD guys about what we should support and we got a clear message that we should be targeting single forests (not because multiple forests didn't exist, but because the AD team was encouraging folks to move to a single forest). Near the end of the release cycle of O11 (summer 2003), it was pretty clear multiple forests were going to be with us for a long time. That left us with very little time to address this deployment scenario.

You can see this naivete in two different places:

People picker
Can only pick from one forest, the one in which the Sharepoint Server is deployed on

Profiles and MySites
Create a MySite and Profile page for each account even though they are for the same person
Org. Charts on the profile page contain incomplete or duplicate entries
Audience targeting works inconsistently for folks who have multiple login accounts

So what are we going to do about it?

First we reduced the many multi-forest topologies to two basic types:

1. Resource Forest
This happens when the Sharepoint deployment is done in a separate forest from the login accounts. This deployment is often driven by the way Exchange and LCS are deployed in the corporation. The Sharepoint/Exchange/LCS forest has shadown, non-login accounts that contain the metadata about the user, but the user actually logs in to a separate forest. The resource forest trusts the login forest, but not the other way around.

2. Multi-login Forests
This happens when there are one or more forests that trust each other, but a single person has accounts in more than one forest. This could happen in many ways, an instructive example is in an merger or acquisition. Both companies had their own forest and after the merger/acquisition, the forests were made to trust each together. Lots of apps depend on the forest structure, so for some people accounts are given in both forests to access the apps.

Note: The right domain should be called Domain2

Now, let's a take look at the two problem areas:

People Picker
Note: This feature is present in Beta2

For the people picker, WSS now allows you to pick people from multiple forests (even across the wrong way of a 1-way trust). The way they do this is by registering your forest and the credentials required to access it for a given Web App via the stsadm tool.

> stsadm.exe -o setproperty -url http://server:port -pn "peoplepicker-searchadforests" -pv "forest:foo.corp.com;domain:bar.foo.corp.com", LoginName, P@ssword

The people picker code will basically iterate through each and every forest (or auth provider) until is resolves a given username. This allows for a simple model to pick people across both the resource forest and multi-login forest topologies.

People and Personalization features
Note: This feature MAY not be in Beta2

Office Server has a number of resources/objects that are identified with a person -- his profile, colleagues, org. hierarchy, mysite, audiences, etc. Multiple forests generate more than one identifier for the same person - different login name, different SID.

So, the problem is how to reconcile the two accounts to one consistent user experience.

In the resource forest case:

When we import a User object from the Resource forest, we create a profile that is ID'd by resource\user1. However, we need to identify it by the real login account of the user, corp\user1, so that you can find the profile when the user logs into Sharepoint as corp\user1. If we didn't do the reconciliation, the profile would be identified by "resource\user1" and the user would be logged in as "corp\user1" and never the two shall meet.

In order to do this, we follow the DN to the master account by looking at the ms-ds-Source-Object-DN** attribute in the User object. When you setup the Directory Connection in Office Server, you will be asked for the login and password for the account that has access to the login forest.

In the Multi-login forest case:

For users who have a login account in each of the forests, we need to correctly map one login user to the other. This is easily done with the msdsSourceObjectDN attribute I mentioned earlier. However, we need to verify the user experience for each account and see whether the "right" thing has happened.

A couple of definitions for the examples to make sense:
1. There are two accounts domain1\user and domain2\user
2. They are in different forests that trust each other
3. Domain1\user is the "master" account of Domain2\user (relationship encoded in AD attribute, populated via MIIS)

Existing features and their expected behaviour:

1. Profile page and object model
Maintain the list of alternate accounts by which the profile is identified. When you try to find the profile of the user using either account, return the same profile (the one of the master account).

2. MySite
Regardless of which account you are logged-in as, creating a MySite will create one using the master account (http://server/personal/user or http://server/personal/domain1_user), but will add the alternate login account(s) as administrators to the site.

3. People Search
Search for people of either accountname (domain1\user or domain2\user) will return the same result, of domain1\user

4. Audiences
Audiences will only contain master accounts. So, during compilation, any rule that contained a slave account will get internally treated like it's master account. For example, All people reporting under "domain2\user" will get treated like "domain1\user". Since we reconcile all accounts, the management hierarchy will be exactly the same for both accounts.

5. Import from Business Data Catalog
Since we are depending on the fact that there is a master account, we will only import data into the profile store that can be identified by the master account. For example, imagine there is an HR people table or webservice. When we try to import the employee id via the BDC, the record for that employee needs to be identified by "domain1\user" not by "domain2\user".

6a. WSS Sync - Memberships
We would have to treat sites in which domain1\user is a member of as well as sites in which domain2\user is a member of as though they belong to the same user, of domain1\user. That will generate the right list of sites. That's not enough.

In order to get the right roll-up of documents and tasks, we would need to issue a query that is something is the equivalent of "SELECT docs FROM member site WHERE author = domain1\user OR author = domain2\user"

6b. WSS Sync - Profile properties
We will need to update the user table rows in the WSS site collection for both domain1\user and domain2\user. This will have the desired effect where the user goes to his MySite and uploads his picture. This info will then be sync'd to every WSS site regardless of whether the user logins in as domain1\user or domain2\user.