Saturday, July 5, 2008

Some Simple Tasks doing programmatically in MOSS 2007:

  1. Executing CAML Query :

SPWeb MyWeb = SPContext.Current.Web;

SPList listDocTypes = MyWeb.Lists["HR Document Type Sub Category"];

Get the list you want to execute query

SPQuery ContentQuery = new SPQuery();

// declaring SPQuery object

ContentQuery.Query = " Name='HRMainCategory'/>" + docCategory.ToString() + "";

//writing Query : is equivalent to select * where 'HRMainCategory' =???

SPListItemCollection items = listDocTypes.GetItems(ContentQuery);

// get the filtered items from List and store it in ListCollectionItems

_DrpDocumentTypeSubCategory.Items.Add("Please Select...");

// iterate and consume items in Drop down

foreach (SPListItem singleItem in items)

{

_DrpDocumentTypeSubCategory.Items.Add(singleItem["HRDocumentTypesSubCategory"].ToString());

}

  1. Cancelling WorkFlow

using Microsoft.SharePoint.Workflow;

SPList currentList = SPContext.Current.List;

// get current list

SPListItem item = (SPListItem)SPContext.Current.Item;

// get current item

// set item moderation to approved

item.ModerationInformation.Status = SPModerationStatusType.Approved;

item.File.Approve("Already Approved Document");

SPWorkflowManager.CancelWorkflow(item.Workflows[0]);

// cancel the workflow



Kind Regards


Muhammad Kaisar wadiwala

Wednesday, June 25, 2008

Custom Searching on Meta data Programmatically

Custom Searching on Meta data Programmatically:

One of the greatest features of MOSS 2007 is to have user defined Meta data properties, you can have lots and lots meta data attributes associated with your list item, document library documents.

Recently I was working on document management system, where user had tons of properties to be associated with documents in there document library. As you know one of the best ability of MOSS 2007 is searching, unfortunately not everything in MOSS 2007 comes out of box, just like your custom Meta data properties will not come by default on Advance Search Box, but to enable it requires simple step. I am assuming you know how to configure advance search box web part. Nevertheless it is very easy, just drop Advance search box web part and Search core result web part on your page (Can be on separate page as well). In advance search web part, specify the path for the result page that’s it your good to go for searches. Crawl the web site and you will see searches coming up.
Now to configure search on your custom Meta data properties follow the following steps:
1. All your custom properties are not by default crawled, to make it crawled by search engine your need to map it first.
2. To map goto Central Admin >> Shared Service Provider >> Search Settings >> Map Metadata Properties
3. Click New Managed Property Name it and add mapping to it , For example you will give your property name “PrpDocumentCategory” , once you click add mapping type in the name you gave your column and click find MOSS will fetch it for you select it and hit ok and OK again.
4. Repeat this step For all your Custom properties.
5. Crawl your Web Application

Now you have successfully mapped your custom properties to crawled properties , but still you won’t see list of your properties in Advance Search Box To enable it another simple configuration is required:

1. Take properties of your advance search box web part and click properties and select browse button , a dialog will appear copy the entire XML to notepad for easy editing and save it as xml and open in it on some XML editor.
2. Find the section and add following tag for all of your mapped properties :

In our case

Repeat for all of your properties.
3. In Last section , that section you want property to appear like all result , documents ,excel file etc and insert following tags


Now you will see every property in drop down list corresponding to the result type you selected. Search for it you will see every thing working perfect.
Now lets go into programming side , now what if you want search to consume in your custom web page or web part or as a matter of fact custom windows application.
MOSS 2007 give 2 option to do search programmatically :
• Creating Search Queries Programmatically by Using the Search Object Model in SharePoint Server 2007
• Creating Search Queries Programmatically by Using the Search Web Service in SharePoint Server 2007

Lets go into sample script using object model of sharepoint assuming your in sharepoint context (web part or web page):

1. First step you need to reference following Assembly : “Microsoft.Office.Server.Search.dll”
2. Include following name space in your code:
a. using System;
b. using System.Runtime.InteropServices;
c. using System.Web.UI;
d. using System.Web.UI.WebControls.WebParts;
e. using System.Xml.Serialization;
f. using Microsoft.Office.Server.Search;
g. using Microsoft.Office.Server.Search.Query;
h. using Microsoft.SharePoint;
i. using Microsoft.SharePoint.WebControls;
j. using Microsoft.SharePoint.WebPartPages;
k. using System.Data;

protected override void Search()
{

String strEmployeeID=”ABC”;
SPSite site = SPContext.Current.Site;

// Create new site from current context

KeywordQuery kwq = new KeywordQuery(site);

// create keyword object


kwq.QueryText = "EmployeeID:"+strEmployeeID;

// set the query text Where EmployeeID property is equal to ABC
// to include property you can use plus sign and to exclude property value from result you can use minus sign
// for example EmployeeID:ABC -DepartmentID:HR
// this will fetch all documents having property value EmployeeID abc but not those document having DepartmetnID:HR

kwq.ResultTypes =ResultType.RelevantResults;

ResultTableCollection results =kwq.Execute();

//execute the Query

ResultTable resultTable =results[ResultType.RelevantResults];

//get the first collection of relevlant result

while (resultTable.Read())
{
resultTable.GetString(5);
resultTable.GetString(2);
resultTable.GetString(6);
resultTable.GetString(8);
resultTable.GetString(3);
resultTable.GetString(4);
}
// iterate the result set do formatting or what ever u want, consume result in web part or page
}

Next time I will tell you how to consume MOSS 2007 search web service and how to use full text SQL query in MOSS 2007 OBJECT model.For more quires you can shoot me an email.



Kind Regards :

Muhammad Kaisar Wadiwala

Thursday, June 12, 2008

Creating Custom Edit Web Part to update Metadata

Recently at customer side, I faced some difficult task, Customer had following requirements:

1. Customer Wanted Meta data properties called Business units (Departments), Project and Project Phases.
2. The project had looks up field for Business units and similarly project phases had projects has look up field.
3. Customer wanted cascading on the drop down list, like once user selected Business unit the project should be filtered on the basis of selection and similarly project phases should be filtered on projects.
4. All the values of these should come from ORACLE E-Business Application and not from any list in share point.

Off these I thought of using Data View Part and/Or BDC to connect to oracle database, but then I realized Cascading is not supported Out-of –box by MOSS 2007, so for customizing edit form I ran out of ideas’ , I googled I searched read every article I can to find solution for the Cascading drop down , the nearest I came to finding solution was on this blog http://datacogs.com/datablogs/archive/2007/08/26/641.aspx , they guy has created its own field for parent and child drop down list which works perfectly, but I didn’t suite me because this works on single level and I had 2 level of cascading combo , I tired to customize the fields but again run out of ideas. So I decided to think as ASP.NET developer which is my core strength, I could not believe I can be defeated easily by MOSS 2007 with this simple requirement.

Finally I decided to create my own web part, and place it on edit form,
But creating this required me to dig deep in MOSS 2007 object model; I am assuming all of you the basic science and anatomy of Web Parts so let’s start with the code:


Here are the control declaration parts in the code:

#region "Control Declaration"
private DropDownList _DrpBusinessUnit;
private DropDownList _DrpProjects;
private DropDownList _DrpProjectPhases;
private DropDownList _DrpContentType;
private PeopleEditor _TxtAuthorName;
private PeopleEditor _TxtForwardedBy;
private TextBox _TxtDocumentCreationDate;
private TextBox _TxtSummary;
private TextBox _TxtDocumentType;
private TextBox _TxtDoucmentCategory;
private TextBox _TxtDocumentSubject;
private TextBox _TxtRetentionPeriod;
private DropDownList _DrpWorkInProgress;
private TextBox _TxtArchiveLocation;
private TextBox _TxtSecurityLevel;
private PeopleEditor _TxtSecurityAdministartor;
private PeopleEditor _TxtAccessNotication;
private TextBox _TxtMediyaType;
private TextBox _TxtFileType;
private TextBox _TxtFilePath;
private TextBox _TxtDocumentExpiryDate;
private TextBox _TxtDocumentExpiryNotification;
private PeopleEditor _TxtPersonToBeNotified;
private TextBox _TxtRecievedFrom;
private Button _BtnSave;
private Button _BtnCancel;
private TextBox _TxtTitle;
#endregion

Notice People Editor in here, we will look in some what detail how to use it.

Next fire Protected override void CreateChildControls() ; here we will add object to web part container and add events for over drop downs , obviously I have stripped down the method , for full listing please see the attached source code


// create a new instance of drop down list
// give it ID
// Set AutoPost True
//attach new event handler
//add new control to web part

this._DrpBusinessUnit = new DropDownList();
this._DrpBusinessUnit.ID = "DrpBusinessUnit";
this._ DrpBusinessUnit.AutoPostBack = true;
this._ DrpBusinessUnit.SelectedIndexChanged += new EventHandler(DrpBusinessUnit_SelectedIndexChanged);
this.Controls.Add(_DrpBusinessUnit);


this._DrpProjects = new DropDownList();
this._DrpProjects.ID = "DrpProjectName";
this._ DrpProjects.AutoPostBack = true;
this._ DrpProjects.SelectedIndexChanged += new EventHandler(DrpProjects_SelectedIndexChanged);
this.Controls.Add(_DrpProjects);

this._DrpProjectPhases = new DropDownList();
this._DrpProjectPhases.ID = "DrpProjectPhases";
this._ DrpProjectPhases.AutoPostBack = true;
this._ DrpProjectPhases.SelectedIndexChanged += new EventHandler(DrpProjectPhases_SelectedIndexChanged);
this.Controls.Add(_DrpProjectPhases);

………………..

this._BtnSave = new Button();
this._BtnSave.ID = "BtnSave";
this._BtnSave.Text = "OK";
this._BtnSave.Click += new EventHandler(BtnSave_Click);
this._BtnSave.CssClass = "ms-ButtonHeightWidth";
this.Controls.Add(_BtnSave);


this._BtnCancel = new Button();
this._BtnCancel.ID = "BtnCancel";
this._BtnCancel.Text = "Cancel";
this._BtnCancel.CssClass = "ms-ButtonHeightWidth";
this.Controls.Add(_BtnCancel);


this._DrpContentType = new DropDownList();
this._DrpContentType.ID = "DrpContent Type";
this._DrpContentType.AutoPostBack = true;
this._DrpContentType.SelectedIndexChanged += new EventHandler(DrpContentType_SelectedIndexChanged);
this.Controls.Add(_DrpContentType);
Populate_ContentTypes();
// I had multiple contnent type we will see this method in detail
GetCurrent_Metadata();
// now get existing metadata if any from the list item or document library from moss 2007
Populate_BussinessInit()
// popluate Business unit combo from oracle


private void Populate_ContentTypes()
{
SPContentTypeCollection ContentTypes = SPContext.Current.List.ContentTypes;
// get all the content types associate with current list and store it in contnet collection
foreach (SPContentType spc in ContentTypes)
{
// iterate collection and add it in drop down for content types
_DrpContentType.Items.Add(spc.Name.ToString());
}

_DrpWorkInProgress.Items.Add("Draft");
_DrpWorkInProgress.Items.Add("Version");
_DrpWorkInProgress.Items.Add("Final");


}

public void GetCurrent_Metadata()
{
try
{


SPWeb MyWeb = SPContext.Current.Web;
// cut current web collection from the context of this web part in order to make it
// generic on list
SPList currentList = SPContext.Current.List;
// get the current list from the context
SPListItem item = (SPListItem)SPContext.Current.Item;
// get the current item from the current list context

foreach (Control cnt in this.Controls)
// Iterate each and every control in the web part that we added\
{
string CID = cnt.ID.ToString().Replace("Txt","").Replace("Drp","");
// now just in order to save time what i did , was set ID of each control
// as the same name of list column in order to bind them with prefix txt or drp
// we will remove it to get column name in the list




if (cnt.GetType().ToString() == "System.Web.UI.WebControls.TextBox")
{
// check if the control is type of text box
if (item[CID] != null)
// item is not null from the list columns
{
// create a tempbox and parse current control as textbox
TextBox temp = (TextBox)cnt;
temp.Text = item[CID].ToString();
// set value of this text box from value in the list item
}
}
else if (cnt.GetType().ToString() == "System.Web.UI.WebControls.DropDownList")
{ // if type of dropdownlist
if (item[CID] != null)
{ // item value is not null

// have to provide check at later stages.
try
{
// find the current item in t he drop down list and make it as selected
((DropDownList)cnt).Items.FindByText(item[CID].ToString()).Selected = true;
}
catch
{

}

}
}
else if (cnt.GetType().ToString() == "Microsoft.SharePoint.WebControls.PeopleEditor")
{ // if its people editior
if (item[CID] != null)
{
// get the comma sperate values from the item list
//people editor store the account names in this format
// 1;#Account;45;#AccountName
// where intengers are the Sharepoint user ID that MOSS 2007 gives it to each object
// in active directory
string strCommaSperatedValues = item[CID].ToString().Replace("#", "").ToString();
string[] strAccounts = strCommaSperatedValues.Split(';');
// split it
strCommaSperatedValues = "";
foreach (string strAccount in strAccounts)
{ // itreate it and check which one's are email id's
if (strAccount.Contains("@") == true)
{
strCommaSperatedValues += strAccount + " ; ";
// store in temp varialbe
}
}
((PeopleEditor)cnt).CommaSeparatedAccounts = strCommaSperatedValues ;
// assign the string to people editor
((PeopleEditor)cnt).Validate();
// this method validates the entry in people editor just like CTRL + K , but some time even with
//valid entry it was not working not sure what the problem was

}


}

}


// smilary with author people editior
_TxtAuthorName.CommaSeparatedAccounts = item["AuthorName"].ToString().Replace("#", "").Replace("1", "").Replace(";","");
_TxtForwardedBy.CommaSeparatedAccounts = item["ForwardedBy"].ToString().Replace("#", "").Replace("1", "").Replace(";", "");


}

catch (Exception ex)
{

}

}




private void Populate_BussinessInit
{

/*
declare connection object of oracle client
* create adatpter
* create dataset
* populate dataset by calling fill method
* populate combo
* this part i am working on it but should not be trouble its simple asp.net code

* /
}


public void Update_MetaData()
{

SPWeb MyWeb = SPContext.Current.Web;
// get current website in collection
SPList currentList = SPContext.Current.List;
// get current list
SPListItem item = (SPListItem)SPContext.Current.Item;
// get current item
MyWeb.AllowUnsafeUpdates = true;
// you have to allow website to accept unsafe updates , becuase by default MOSS 2007
// does not allow programmatic updates to the content types
foreach (Control cnt in this.Controls)
{
// similarly with get methods iterate each controls
//basically this is reverel now from text box we will set item properties
string CID = cnt.ID.ToString().Replace("Txt", "").Replace("Drp", "");
if (cnt.GetType().ToString() == "System.Web.UI.WebControls.TextBox")
{
if (((TextBox)cnt).Text.Length !=0)
item[CID] = ((TextBox)cnt).Text;

}
else if (cnt.GetType().ToString() == "System.Web.UI.WebControls.DropDownList")
{

if (((DropDownList)cnt).SelectedIndex != -1)
{
item[CID] = ((DropDownList)cnt).SelectedItem.Text;
}

}
else if (cnt.GetType().ToString() == "Microsoft.SharePoint.WebControls.PeopleEditor")
{
// Logic explained bellow
}


}
PickerEntity objEntity = (PickerEntity)_TxtAuthorName.ResolvedEntities[0];
// get the first resolved entry from author name people picker as it does not allow multiple values
//parse it as Picker entirty
int UserID = int.Parse(objEntity.EntityData["SPUserID"].ToString());
// get the sharepoint User ID of the selected user

SPFieldUserValue userValue = new SPFieldUserValue(MyWeb, UserID ,objEntity.DisplayText );
// now this is really intersting in order to save people and group you must declare
//SPFieldUserValue class and instantation it with MOSS 2007 userID and Name

item["AuthorName"] = userValue;
// set it authorname columns

item.Update();
// update the items
MyWeb.Update();
//update the web
MyWeb.AllowUnsafeUpdates = false;
// set allowance unsafe update to false again just in case



}

Now rest of the logic is simple ASP.Net fire selected index event of business unit to get the data from oracle stored procedure for project and from project selected index get project phases , add validation what ever you want just like ASP.NET web page. Render the web part they way you want.With the power of ASP.NET behind your code possibles are unlimited now , I just demonstrated to you how to get and update metadata from list.

And Remember to add system.data.oracleclient assembly to full turst level in GAC and MOSS 2007 safe assembly tags in web.config , otherwise you will get security permission error in MOSS 2007.

The web part code is still incomplete but purpose of this post was to demonstrate idea how to do things programmatic ally.

If you need further help do not hesitate to write me at kaisar.wadiwala@gmail.com


Kind Regards ,

Muhammad Kaisar Wadiwala
Microsoft Certified Technology Specialist

Wednesday, June 11, 2008

Hi Everyone

This is just an initiative for better collaboration between us to improve our Skills in order to avoid the difficulties facing during the projects. It will be really use full for everyone to identify the significance of MOSS 2007 and their drawbacks.