Upload
others
View
24
Download
0
Embed Size (px)
Citation preview
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 1
How to Create Duet SharePoint
Web Parts
Applies to:
Duet Enterprise for Microsoft Sharepoint and SAP version 1.5 and above, SAP Netweaver Gateway, SharePoint BDC programming.
Summary
This article describes how to create Web Parts that are using BDC’s to connect SharePoint with Duet Enterprise.
Author: Ravi Sharma
Company: C2C Consulting
Created on: 30 January 2011
Author Bio
Ravi Sharma is a Development Architect and solution manager working for C2C consulting in Germany. His current Tasks: Duet Enterprise For Microsoft SharePoint and SAP, SAP NetWeaver Gateway and iPhone / Android Apps, SAP ESOA Tools & Utilities SAP IDM & GRC Integration. Knowledge of SAP ABAP, Cross Applications, ALE/IDOC, RFC's qRFC, tRFC, BADI, OOP's Concepts, CCMS and Solution Manager, SAP RFID, SAP Dynpro, SAP ABAP Webdynpro, SAP Net weaver, DUET 1.5, ABAP and Java Web services.
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 2
Table of Contents
Introduction ..................................................................................................................................................... 3
Expense Approval ........................................................................................................................................... 3 External Lists ............................................................................................................................................................... 3
Web Parts .................................................................................................................................................................... 4
HR Transfer ................................................................................................................................................... 10 External Lists ............................................................................................................................................................. 12
Web Parts .................................................................................................................................................................. 15
Utility Functions .......................................................................................................................................................... 22
Using the Console Applications .................................................................................................................... 23
Creating the project ....................................................................................................................................... 25
Adding Code ................................................................................................................................................. 29
Deploying the Code ....................................................................................................................................... 30
Add the Web Parts to SharePoint ................................................................................................................. 31
Related Content ................................................................................................................................................ 32
Copyright........................................................................................................................................................... 33
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 3
Creating Duet SharePoint Web Parts
Introduction
This document describes how to create Web Parts for SharePoint and Duet Enterprise and how to deploy them. The Web Parts used in this sample were created for a Proof of Concept to show how the interaction with SAP and SharePoint works.
Expense Approval
In the Expense Approval Process a manager can approve Travel Expenses for his employees.
The HR Transfer consists of one external list and one Web Part
External Lists
The Web Part uses the Duet build-in WorkflowTask External Content Type
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 4
The WorkflowTask has a method wfUpdate which has to be called to update the SAP Task
Parameters are
0001 Approve
0003 Reject
Web Parts
The Web Part first retrieves a list of active Workflow tasks. The Currency and the Amount are passed as extended properties private void ListTasks() { SPWeb oSPWeb2; ExpenseTaskList.Clear(); SPSite oSPSite = SPControl.GetContextSite(Context); using (oSPWeb2 = oSPSite.OpenWeb(approvalSite)) { SPListCollection collList = oSPWeb2.Lists; SPList timesheets = oSPWeb2.Lists["Workflow Tasks"]; SPListItemCollection collItem = timesheets.Items;
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 5
int itemCount = 0; foreach (SPListItem oItem in collItem) { string workflowData = SPWorkflowTask.GetWorkflowData(oItem); Dictionary<string, string> workflowDict = getOwsValues(workflowData); string ows_TaskInstanceParentId = getOwsValue(workflowDict, "ows_TaskInstanceParentId"); string status = oItem["Status"].ToString().Trim().ToLower(); if (status != "completed") { string ows_Title = getOwsValue(workflowDict, "ows_Title"); string ows_ParentInitiator = getOwsValue(workflowDict, "ows_ParentInitiator"); string ows_StartDate = getOwsValue(workflowDict, "ows_StartDate"); string ows_DueDate = getOwsValue(workflowDict, "ows_StartDate"); string ows_WorkflowLink = getOwsValue(workflowDict, "ows_WorkflowLink"); string from = ows_ParentInitiator; string sent = convertDate(ows_StartDate); string workflowLink = ows_WorkflowLink.Replace("'", ""); string[] a = workflowLink.Split(','); SPListItem sapBusinessDocListItem = oSPWeb2.GetListItem(a[0]); XmlDocument sapBusinessXmlDoc = new XmlDocument(); XmlNamespaceManager nsm = new XmlNamespaceManager(sapBusinessXmlDoc.NameTable); nsm.AddNamespace("z", "#RowsetSchema"); sapBusinessXmlDoc.LoadXml(sapBusinessDocListItem.Xml); string ows_AMOUNT = sapBusinessXmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_AMOUNT"].Value; string ows_CURRENCY = sapBusinessXmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_CURRENCY"].Value; string amount = ows_CURRENCY + " " + ows_AMOUNT; string subject; try { string ows_description = sapBusinessXmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_ZDESCRIPTION"].Value; subject = ows_description; } catch (Exception) { subject = splitTitle(ows_Title); } string ows_FileDirRef = getOwsValue(workflowDict, "ows_FileDirRef"); string fileDirRef = ows_FileDirRef.Replace("'", ""); a = fileDirRef.Split('#'); string link = @"/" + a[1] + "/dispform.aspx?ID=" + oItem.ID.ToString().Trim(); string due = convertDate(ows_DueDate); ExpenseTaskList.Add(new ExpenseTaskEntry(
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 6
oItem.ID.ToString(), oItem.Title.ToString(), SPEncode.HtmlEncode(subject), SPEncode.HtmlEncode(from), SPEncode.HtmlEncode(sent), SPEncode.HtmlEncode(amount), SPEncode.HtmlEncode(due), link, status, SPEncode.HtmlEncode(ows_TaskInstanceParentId) )); itemCount++; } } if (itemCount == 0) { lblNoItems.Visible = true; DataGrid1.Visible = false; btnSubmitTasks.Visible = false; } } DataGrid1.DataSource = ExpenseTaskList; DataGrid1.DataBind(); }
When the user approves or rejects a task the SAP Workflow is triggered.
const string opApproved = "Approved"; const string opRejected = "Rejected";
private void SubmitTasks() { SPWeb oSPWeb2; string statusMsg = ""; SPSite oSPSite = SPControl.GetContextSite(Context); using (oSPWeb2 = oSPSite.OpenWeb(approvalSite)) { SPList timesheets = oSPWeb2.Lists["Workflow Tasks"]; SPListItemCollection collItem = timesheets.Items; foreach (SPListItem oItem in collItem) { foreach (DataGridItem item in DataGrid1.Items) { Label lbl = (Label)item.FindControl("ID"); int TaskID = Int32.Parse(lbl.Text); if (oItem.ID == TaskID) { string operation = "";
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 7
RadioButtonList rbl = (RadioButtonList)item.FindControl("Selection"); string clickedOperation = rbl.SelectedValue.ToString(); TextBox txt = (TextBox)item.FindControl("Reason"); string reason = txt.Text; if (clickedOperation == "Approve") operation = opApproved; if (clickedOperation == "Reject") operation = opRejected; if (operation == opApproved || operation == opRejected) { string workflowData = SPWorkflowTask.GetWorkflowData(oItem); Dictionary<string, string> workflowDict = getOwsValues(workflowData); string ows_TaskInstanceParentId = getOwsValue(workflowDict, "ows_TaskInstanceParentId"); string owsOperation = (operation == opApproved ? "0001" : "0003"); { string result = updateSAPTask(ows_TaskInstanceParentId, owsOperation, reason); if (result == "") { try { updateSharePointTask(oItem, operation); statusMsg = statusMsg + ows_TaskInstanceParentId + " updated successfully <br /><br />"; } catch (Exception ex) { statusMsg = statusMsg + ows_TaskInstanceParentId + " failed: <br />" + SPEncode.HtmlEncode(ex.Message) + "<br /><br />"; } } else { statusMsg = statusMsg + ows_TaskInstanceParentId + " failed: <br />" + SPEncode.HtmlEncode(result) + "<br /><br />"; } } } } } } }
lblPopupInfo.Text = "Thank you. Your transaction has been submitted"; lblTransactionID.Text = statusMsg; ModalInfo.Show(); ListTasks();
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 8
}
The reference to the SAP Workflow Task is passed as ows_TaskInstanceParentId.
private string updateSAPTask(string ows_TaskInstanceParentId, string owsperation, string comment) { string result = ""; using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.Site))) { IMetadataCatalog databaseCatalog = null; BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); } string @namespace = "SAP.Office.DuetEnterprise.Workflow"; string entityName = "WorkflowTask"; string lsiName = "WorkflowWebService"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem(); ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; INamedMethodDictionary methodDictionary = entity.GetMethods(); IView view = entity.GetUpdaterView("wfUpdate"); IMethodInstance method = entity.GetMethodInstance("wfUpdate", MethodInstanceType.Updater); IParameterCollection parameters = method.GetMethod().GetParameters(); ITypeReflector reflector = parameters[0].TypeReflector; ITypeDescriptor rootTypeDescriptor = parameters[0].GetRootTypeDescriptor(); object[] methodParamInstances = method.GetMethod().CreateDefaultParameterInstances(method); Object instance = methodParamInstances[0]; ITypeDescriptor actionTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[0]; ITypeDescriptor bcsCorrelationIdTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[1]; ITypeDescriptor commentsTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[2]; ITypeDescriptor iwWfTaskIdTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[3]; ITypeDescriptor outcomeTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[4]; ITypeDescriptor reassignedToTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[5];
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 9
reflector.Set(actionTypeDescriptor, rootTypeDescriptor, ref instance, "EXEC"); reflector.Set(bcsCorrelationIdTypeDescriptor, rootTypeDescriptor, ref instance, ""); reflector.Set(commentsTypeDescriptor, rootTypeDescriptor, ref instance, comment); reflector.Set(iwWfTaskIdTypeDescriptor, rootTypeDescriptor, ref instance, ows_TaskInstanceParentId); reflector.Set(outcomeTypeDescriptor, rootTypeDescriptor, ref instance, owsperation); reflector.Set(reassignedToTypeDescriptor, rootTypeDescriptor, ref instance, ""); try { entity.Execute(method, lobSysteminstance, ref methodParamInstances); } catch (Exception ex) { result = ex.InnerException.Message; } finally { if (lobSysteminstance != null) lobSysteminstance.FlushConnections(); } return result; } }
The SharePoint Task has also to be updated Operation is "Approved" or "Rejected"
private void updateSharePointTask(SPListItem oItem, string operation) { Hashtable ht = new Hashtable(); ht["Completed"] = "TRUE"; ht["PercentComplete"] = 1f; ht[SPBuiltInFieldId.Comments] = "Test" + operation; ht[SPBuiltInFieldId.TaskStatus] = "Completed"; ht[SPBuiltInFieldId.WorkflowOutcome] = operation; ht[SPBuiltInFieldId.FormData] = SPWorkflowStatus.Completed; ht["ows_TaskStatus"] = operation; bool result = SPWorkflowTask.AlterTask(oItem, ht, true); }
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 10
HR Transfer
The HR Transfer is used to transfer an employee from one manager to another manager
It consists of three external lists and three Web Parts.
A HR Transaction in started by the first Manager
The second manager gets the Approval Tasks on his workflow list
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 11
To complete and approve the Transfer he has enter the position, reason, schedule and salary
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 12
External Lists
The Web Parts are using the following custom External Content Types
It exposes two Methods:
ZGET_EMPLOYEELIST retrieves a list for employees for the current logged in manager
ZREAD_EMPLOYEE gets the details for an employee
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 13
The Employee Transfer Content Type is used to manage the Transfers
It has three Methods:
CreateEmployeeTransfer creates a new Transfer Workflow on the backend
ReadEmpTransferByID gets the details for a started Transfer
UpdateEmployeeTransfer updates the workflow to approved or rejected
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 14
The third Content Type is used to find the open positions that a manager has to fill
The two methods are
FindOpenPositions gets a list of vacancies for the current manager
ReadOpenPostionsByID gets a single vacancy
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 15
Web Parts
The Start Transaction Web Part calls the Backend to start the SAP Workflow private string startEmployeeTransfer(string category, string process, string country, string empObjectID, string manObjectID, string effectiveDate, string note) { using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.Site))) { BdcService service = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); IMetadataCatalog databaseCatalog = null; BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); } string @namespace = @"https://<hostname>:<port>/tasks"; string entityName = "EmployeeTransfer"; string lsiName = "SCLEmployeeTransfer"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem(); ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; IView view = entity.GetCreatorView("CreateEmployeeTransfer"); IFieldValueDictionary fieldValueDictionary = view.GetDefaultValues(); IFieldCollection fieldCollection = view.Fields; foreach (IField field in fieldCollection) { try { fieldValueDictionary[field.Name] = ""; } catch (Exception) { } } fieldValueDictionary["EmpSclKey"] = "Dummy"; fieldValueDictionary["Category"] = category; fieldValueDictionary["Process"] = process; fieldValueDictionary["CountryOfEmp"] = country; fieldValueDictionary["EmpObjectType"] = "P "; fieldValueDictionary["EmpObjectID"] = empObjectID; fieldValueDictionary["ManObjectType"] = "P "; fieldValueDictionary["ManObjectID"] = manObjectID; fieldValueDictionary["EffectiveDate"] = effectiveDate; fieldValueDictionary["Note"] = note; fieldValueDictionary["HRPosObjID"] = "0";
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 16
Identity id = entity.Create(fieldValueDictionary, lobSysteminstance); if (id != null) { Object[] returnValues = id.GetIdentifierValues(); return returnValues[0].ToString(); } else { return ""; } } }
Reading the task list for the receiving manager is similar to the Expense Approval Web Part. The Reference to the SAP Transfer ID is passed as extended property in ows_TRANSFER_GUID. The description ows_ZDESCRIPTION is also passed as xprop. private void ListTasks() { SPWeb oSPWeb2; HRTaskList.Clear(); string txt = ""; SPSite oSPSite = SPControl.GetContextSite(Context); using (oSPWeb2 = oSPSite.OpenWeb(approvalSite)) { SPListCollection collList = oSPWeb2.Lists; SPList timesheets = oSPWeb2.Lists["Workflow Tasks"]; SPListItemCollection collItem = timesheets.Items; int itemCount = 0; foreach (SPListItem oItem in collItem) { string workflowData = SPWorkflowTask.GetWorkflowData(oItem); Dictionary<string, string> workflowDict = getOwsValues(workflowData); string ows_TaskInstanceParentId = getOwsValue(workflowDict, "ows_TaskInstanceParentId"); string status = oItem["Status"].ToString().Trim().ToLower(); if (status != "completed") { string ows_Title = getOwsValue(workflowDict, "ows_Title"); string ows_ParentInitiator = getOwsValue(workflowDict, "ows_ParentInitiator"); string ows_StartDate = getOwsValue(workflowDict, "ows_StartDate"); string ows_DueDate = getOwsValue(workflowDict, "ows_StartDate"); string ows_WorkflowLink = getOwsValue(workflowDict, "ows_WorkflowLink"); string from = ows_ParentInitiator; string sent = convertDate(ows_StartDate); string ows_FileDirRef = getOwsValue(workflowDict, "ows_FileDirRef"); string fileDirRef = ows_FileDirRef.Replace("'", ""); string[] a = fileDirRef.Split('#');
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 17
string link = @"/" + a[1] + "/dispform.aspx?ID=" + oItem.ID.ToString().Trim(); string due = convertDate(ows_DueDate); string workflowLink = ows_WorkflowLink.Replace("'", ""); a = workflowLink.Split(','); SPListItem sapBusinessDocListItem = oSPWeb2.GetListItem(a[0]); XmlDocument sapBusinessXmlDoc = new XmlDocument(); XmlNamespaceManager nsm = new XmlNamespaceManager(sapBusinessXmlDoc.NameTable); nsm.AddNamespace("z", "#RowsetSchema"); sapBusinessXmlDoc.LoadXml(sapBusinessDocListItem.Xml); string transferID = sapBusinessXmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_TRANSFER_GUID"].Value; transferID = transferIdPrefix + transferID + transferIdPostfix; string ows_description = sapBusinessXmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_ZDESCRIPTION"].Value; string subject = ows_description; string workflowID = "000000000"; HRTaskList.Add(new HRTaskEntry( oItem.ID.ToString(), oItem.Title.ToString(), SPEncode.HtmlEncode(subject), SPEncode.HtmlEncode(from), SPEncode.HtmlEncode(sent), SPEncode.HtmlEncode(due), link, status, transferID, SPEncode.HtmlEncode(ows_TaskInstanceParentId), SPEncode.HtmlEncode(workflowID) )); itemCount++; } } if (itemCount == 0) { lblNoItems.Visible = true; DataGrid1.Visible = false; } } DataGrid1.DataSource = HRTaskList; DataGrid1.DataBind(); }
When the transfer is finished the CompleteTransfer Web Part is used. First the Transfer Data for is retrieved from the backend. Parameter is the TransferID which was passed as xprop in the previous Web Part.
private void getTransferData(string id) {
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 18
using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.Site))) { BdcService service = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); IMetadataCatalog databaseCatalog = null; BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); } string @namespace = @"https://<hostname>:<port>/tasks"; string entityName = "EmployeeTransfer"; string lsiName = "SCLEmployeeTransfer"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem(); ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; IView view = entity.GetSpecificFinderView("ReadEmpTransferByID"); IFieldValueDictionary valueDictionary = view.GetDefaultValues(); IFieldCollection fieldCollection = view.Fields; IEntityInstance result = entity.FindSpecific(new Identity(id), "ReadEmpTransferByID", lobSysteminstance); foreach (IField field in fieldCollection) { if (result[field.Name] != null) TransferData.Add(field.Name, result[field.Name].ToString()); else TransferData.Add(field.Name, ""); } } } Then the list of vacant position is retrieved from the backend. As parameter the currently logged in username is passed. The result is added to a Dictionary<string, string> which holds the positions that are displayed on the UI.
private void getOpenPositions(string managerName) { using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.Site))) { BdcService service = SPFarm.Local.Services.GetValue<BdcService>(String.Empty);
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 19
IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); IMetadataCatalog databaseCatalog = null; BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); } string @namespace = @"https://<hostname>:<port>/tasks"; string entityName = "FindOpenPositions"; string lsiName = "SCLFindOpenPositions"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem(); ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; IMethodInstance methodInstance = entity.GetMethodInstance("FindOpenPostions", MethodInstanceType.Finder); IFilterCollection filters = methodInstance.GetFilters(); foreach (ComparisonFilter filter in filters) { if (filter.Name == "FindByManager") filter.Value = managerName; } IEntityInstanceEnumerator ientityInstanceEnumerator = entity.FindFiltered(filters, lobSysteminstance); Positions.Add("-1", "Select Position"); while (ientityInstanceEnumerator.MoveNext()) { string objectID = ientityInstanceEnumerator.Current["ObjectId"].ToString(); string objectName = ientityInstanceEnumerator.Current["ObjectName"].ToString(); Positions.Add(objectID, objectName); } } }
Updating the SAP Task is a two step process. To get the values and parameters from the backend first the finder view method with ReadEmpTransferByID is called. This is necessary because the input parameters can’t retrieved directly from the updater. The result is similar to result["EmpSclKey"] = "3211_0050568700DF1EE0A1AB7D0FED5389C2_Z_EMP_TRANS_TCE_800"; result["TransferGUID"] = ""; result["TransferID"] = "0050568700DF1EE0A1DABC176924E9C2"; result["Category"] = "11"; result["Process"] = "02"; result["CountryOfEmp"] = "US"; result["Employee"] = "P 00100015"; result["EmpObjectType"] = "P"; result["EmpObjectID"] = "00100015";
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 20
result["RecevingManager"] = "P 00100152"; result["ManObjectType"] = "P"; result["ManObjectID"] = "00100152"; result["EffectiveDate"] = "20110517"; result["Note"] = "Updating"; result["CreatedBy"] = ""; result["CreatorObjectType"] = ""; result["CreatorUserName"] = ""; result["CreatedAt"] = ""; result["HRPosition"] = "Test"; result["HRPosObjType"] = "P"; result["HRPosObjID"] = "50008525"; result["Reason"] = ""; result["Schedule"] = ""; result["Salary"] = "123"; result["CurrencyKey"] = "EUR"; result["Periodicity"] = ""; result["ChangedBy"] = ""; result["ChangedByOtype"] = ""; result["ChangedByObjID"] = ""; result["ChangedAt"] = ""; result["ExtensionContainer1"] = "APPROVED"; result["ExtensionContainer2"] = "000001111957"; result["ExtensionContainer3"] = ""; result["ExtensionContainer4"] = ""; result["ExtensionContainer5"] = ""; result["ExtensionContainer6"] = "";
After setting the parameters to the new values the updater view UpdateEmployeeTransfer is called private string updateSAPTransfer(string transferID, string taskParentID, string hRPosition, string hRPosObjID, string schedule, string reason, string salery, string currencyKey, string periodicity, string decision) { using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.Site))) { BdcService service = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); IMetadataCatalog databaseCatalog = null; BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); } string @namespace = @"https://<hostname>:<port>/tasks"; string entityName = "EmployeeTransfer"; string lsiName = "SCLEmployeeTransfer"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem();
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 21
ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; IView view = entity.GetSpecificFinderView("ReadEmpTransferByID"); IFieldValueDictionary valueDictionary = view.GetDefaultValues(); IFieldCollection fieldCollection = view.Fields; IEntityInstance result = entity.FindSpecific(new Identity(transferID), "ReadEmpTransferByID", lobSysteminstance); IView updateView = entity.GetUpdaterView("UpdateEmployeeTransfer"); IFieldValueDictionary updateValueDictionary = updateView.GetDefaultValues(); IFieldCollection updateFieldCollection = updateView.Fields; result["ExtensionContainer2"] = taskParentID; result["HRPosition"] = "S " + hRPosObjID; result["HRPosObjID"] = hRPosObjID; result["HRPosObjType"] = "S"; if (decision == opApproved) { result["Reason"] = reason; result["Schedule"] = schedule; result["Salary"] = salery; result["CurrencyKey"] = currencyKey; result["Periodicity"] = periodicity; result["ExtensionContainer1"] = opApproved.ToUpper(); } else { result["ExtensionContainer1"] = opRejected.ToUpper(); } IMethodInstance method = entity.GetMethodInstance("UpdateEmployeeTransfer", MethodInstanceType.Updater); IParameterCollection parameters = method.GetMethod().GetParameters(); ITypeReflector reflector = parameters[0].TypeReflector; ITypeDescriptor rootTypeDescriptor = parameters[0].GetRootTypeDescriptor(); object[] methodParamInstances = method.GetMethod().CreateDefaultParameterInstances(method); Object instance = methodParamInstances[0]; int i = 0; foreach (IField field in updateFieldCollection) { string param; ITypeDescriptor typeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[i]; string lobName = typeDescriptor.LobName.ToString(); try { param = result[lobName].ToString(); } catch (Exception) { param = "";
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 22
} reflector.Set(typeDescriptor, rootTypeDescriptor, ref instance, param); i++; } string returnValue = ""; try { entity.Execute(method, lobSysteminstance, ref methodParamInstances); } catch (Exception ex) { returnValue = ex.InnerException.Message; } finally { if (lobSysteminstance != null) lobSysteminstance.FlushConnections(); } return returnValue; } }
To update the SharePoint Task the same code as in ExprenseApproval is used private void updateSharePointTask(SPListItem oItem, string operation) { Hashtable ht = new Hashtable(); ht["Completed"] = "TRUE"; ht["PercentComplete"] = 1f; ht[SPBuiltInFieldId.Comments] = "Update " + operation; ht[SPBuiltInFieldId.TaskStatus] = "Completed"; ht[SPBuiltInFieldId.WorkflowOutcome] = operation; ht[SPBuiltInFieldId.FormData] = SPWorkflowStatus.Completed; ht["ows_TaskStatus"] = operation; bool result = SPWorkflowTask.AlterTask(oItem, ht, true); }
Utility Functions
Most Web Parts are using regular expression to parse the XML files. The .NET XML classes can’t be used because the response is not always well formed. private Dictionary<string, string> getOwsValues(string rawData) { Regex regex = new Regex(@"(ows_[^=]*)='([^=]*)'"); Dictionary<string, string> dict = new Dictionary<string, string>(); MatchCollection mc = regex.Matches(rawData); foreach (Match m in mc) { try { dict.Add(m.Groups[1].Value, m.Groups[2].Value); } catch (Exception) { } } return dict; }
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 23
private string getOwsValue(Dictionary<string, string> ows, string key) { try { return ows[key]; } catch (Exception) { return (""); } }
Using the Console Applications
To develop and test BDC Models it can be useful to test them first in a console application. This has the advantage that no deployment to SharePoint is necessary and the application runs faster because no ASP code is executed. Here is a sample for the FindOpenPostions BDC using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text.RegularExpressions; using System.Xml; using Microsoft.BusinessData.Infrastructure; using Microsoft.BusinessData.MetadataModel; using Microsoft.BusinessData.MetadataModel.Collections; using Microsoft.BusinessData.Runtime; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using Microsoft.SharePoint.BusinessData.Runtime; using Microsoft.SharePoint.BusinessData.SharedService; using Microsoft.SharePoint.Workflow; namespace SharePointTest1 { class Program { const string siteUrl = "https://<hostname>:<port>"; static void Main() { testReadOpenPositions(); Console.ReadLine(); }
private static void testReadOpenPositions() { SPServiceContext context = SPServiceContext.GetContext(new SPSite(siteUrl)); IMetadataCatalog databaseCatalog = null;
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 24
BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty); if (null != bdcService) { databaseCatalog = bdcService.GetDatabaseBackedMetadataCatalog(context); } string @namespace = @"https://<hostname>:<port>/tasks"; string entityName = "FindOpenPositions"; string lsiName = "SCLFindOpenPositions"; IEntity entity = databaseCatalog.GetEntity(@namespace, entityName); ILobSystem lobSystem = entity.GetLobSystem(); ILobSystemInstance lobSysteminstance = lobSystem.GetLobSystemInstances()[lsiName]; INamedMethodDictionary methodDictionary = entity.GetMethods(); IMethodInstance methodInstance = entity.GetMethodInstance("FindOpenPostions", MethodInstanceType.Finder); IFilterCollection filters = methodInstance.GetFilters(); foreach (ComparisonFilter filter in filters) { Console.WriteLine("Filter = {0}", filter.Name); if (filter.Name == "FindByManager") filter.Value = "TABASCOT"; } IEntityInstanceEnumerator ientityInstanceEnumerator = entity.FindFiltered(filters, lobSysteminstance); int i = 0; while (ientityInstanceEnumerator.MoveNext()) { i++; string empSclKey = ientityInstanceEnumerator.Current["EmpSclKey"].ToString(); Console.WriteLine(empSclKey); } Console.WriteLine("No or Records: {0}", i); Console.WriteLine("Ready"); } } }
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 25
Creating the project
First an empty SharePoint 2010 Project/Solution has to be created
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 26
For each Web Part add another Empty SharePoint Project to the Solution
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 27
Add a new Visual Web Part to each project
Add a reference to Microsoft.BusinessData.dll. It’s located in the directory
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 28
The creating the Web Part projects the initially created project can be removed
The Solution should look like this
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 29
Adding Code
Add your code to the Web Parts.
Add also the usings to the code using System; using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Xml; using Microsoft.BusinessData.Infrastructure; using Microsoft.BusinessData.MetadataModel; using Microsoft.BusinessData.MetadataModel.Collections; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using Microsoft.SharePoint.BusinessData.SharedService; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.WebControls; using Microsoft.SharePoint.Workflow;
The Description and Title can be entered in the .Web Part file
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 30
Deploying the Code
The Web Parts can simply build and deployed from the context menu. Sometimes it’s necessary to retract the last deployment from SharePoint
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 31
Add the Web Parts to SharePoint
In SharePoint Designer create a new Web Part Page
The Web Part can be added from the List of available Web Parts
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 32
Related Content
Professional Business Connectivity Services in SharePoint 2010
Scot Hillier, Brad Stevenson / Wrox / February 2011
Duet for Microsoft Office and SAP
http://www.sdn.sap.com/irj/sdn/duet
Duet Enterprise for Microsoft SharePoint and SAP
http://technet.microsoft.com/en-us/library/ff972436.aspx
Microsoft Business Connectivity Services Team Blog
http://blogs.msdn.com/b/bcs/
Everything You Need to Know about BDC
http://SharePointmagazine.net/articles/everything-you-need-to-know-about-bdc-part-1-of-8 (ff)
How to Create Duet SharePoint Web Parts
SAP COMMUNITY NETWORK SDN - sdn.sap.com | BPX - bpx.sap.com | BA - boc.sap.com | UAC - uac.sap.com
© 2011 SAP AG 33
Copyright
© Copyright 2012 SAP AG. All rights reserved.
No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP AG. The information contained herein may be changed without prior notice.
Some software products marketed by SAP AG and its distributors contain proprietary software components of other software vendors.
Microsoft, Windows, Excel, Outlook, and PowerPoint are registered trademarks of Microsoft Corporation.
IBM, DB2, DB2 Universal Database, System i, System i5, System p, System p5, System x, System z, System z10, System z9, z10, z9, iSeries, pSeries, xSeries, zSeries, eServer, z/VM, z/OS, i5/OS, S/390, OS/390, OS/400, AS/400, S/390 Parallel Enterprise Server, PowerVM, Power Architecture, POWER6+, POWER6, POWER5+, POWER5, POWER, OpenPower, PowerPC, BatchPipes, BladeCenter, System Storage, GPFS, HACMP, RETAIN, DB2 Connect, RACF, Redbooks, OS/2, Parallel Sysplex, MVS/ESA, AIX, Intelligent Miner, WebSphere, Netfinity, Tivoli and Informix are trademarks or registered trademarks of IBM Corporation.
Linux is the registered trademark of Linus Torvalds in the U.S. and other countries.
Adobe, the Adobe logo, Acrobat, PostScript, and Reader are either trademarks or registered trademarks of Adobe Systems Incorporated in the United States and/or other countries.
Oracle is a registered trademark of Oracle Corporation.
UNIX, X/Open, OSF/1, and Motif are registered trademarks of the Open Group.
Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, VideoFrame, and MultiWin are trademarks or registered trademarks of Citrix Systems, Inc.
HTML, XML, XHTML and W3C are trademarks or registered trademarks of W3C®, World Wide Web Consortium, Massachusetts Institute of Technology.
Java is a registered trademark of Oracle Corporation.
JavaScript is a registered trademark of Oracle Corporation, used under license for technology invented and implemented by Netscape.
SAP, R/3, SAP NetWeaver, Duet, PartnerEdge, ByDesign, SAP Business ByDesign, and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and other countries.
Business Objects and the Business Objects logo, BusinessObjects, Crystal Reports, Crystal Decisions, Web Intelligence, Xcelsius, and other Business Objects products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of Business Objects S.A. in the United States and in other countries. Business Objects is an SAP company.
All other product and service names mentioned are the trademarks of their respective companies. Data contained in this document serves informational purposes only. National product specifications may vary.
These materials are subject to change without notice. These materials are provided by SAP AG and its affiliated companies ("SAP Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty.