Network Layout

network

In K2\SharePoint MS SQL Express, create a database:Express and create a table:Course

USE [Express]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Course](
[CourseID] [int] IDENTITY(1,1) NOT NULL,
[CourseName] [nchar](50) NOT NULL,
[Description] [nchar](50) NOT NULL,
[Grade] [float] Not NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Course] ADD DEFAULT ((0)) FOR [Grade]
GO


In SQL Server 2008 R2 of computer:queen, create a database: ShareDB and Create a table: Course

USE [ShareDB]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Course](
[CourseID] [int] IDENTITY(1,1) NOT NULL,
[CourseName] [nchar](50) NOT NULL,
[Description] [nchar](50) NOT NULL,
[Grade] [float] Not NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Course] ADD DEFAULT ((0)) FOR [Grade]
GO


 

Visual Studio 2010 Professional is installed on K2.

Create a new project (BdcExpress) based on Business Data Connectity Model

01

 

02

03

04

Replace the Course.vb with Course.vb

Replace the CourseService.vb with CourseService.vb

Inside the link CourseService.vb, the connection points to K2\SharePoint SQL Express server, the local SQL Server.

Private Shared Function getSqlConnection() As SqlConnection
Dim sqlConn As New SqlConnection("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Express;Data Source=K2\SharePoint")
Return (sqlConn)
End Function


Build and deploy the solution

In SharePoint site, create an External List based on the External Content Type:

05

Can read data, Insert data, delete data, and update data


Delete the External Content Type

06


Modify the database connection

Private Shared Function getSqlConnection() As SqlConnection
Dim sqlConn As New SqlConnection("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ShareDB;Data Source=Queen")
Return (sqlConn)
End Function

Build and Deploy the solution

Create an external list based on the new external content type: BdcExpress.Course

You cannot open the external list from Computer Queen.

07

 

 


Follow the link to modify the .bdcm file

Retrieve Username and Password from SSS

set SQL Server 2008 securit mode of Queen computer to SQL Server authentication

Modify the connection string

Private Shared Function getSqlConnection(ByVal username As String, ByVal password As String) As SqlConnection

'Dim sqlConn As New SqlConnection("initial Catalog=sharedb;Data Source=queen;User ID=" & username & ";Password=" & password)

Dim sqlStr As String = "Initial Catalog=ShareDB;Data Source=Queen;User ID=" & username & ";Password=" & password

Dim sqlConn As New SqlConnection(sqlStr)
Return (sqlConn)
End Function

code

 


If you want to use Windows Authentication mode in SQL Server of Queen computer, order BdcMetaMan from Bdc Meta Man.

or download the 14-day trial version Bdc meta man

It is coded in C#.


Project Name:BdcSharp

Add References:

Add a reference to Microsoft.BusinessData.dll (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\)

Add a reference to Microsoft.Office.SecureStoreService.dll (C:\Windows\assembly\GAC_MSIL\Microsoft.Office.SecureStoreService\14.0.0.0__71e9bce111e9429c\)

SQL Server connection string

Initial Catalog=ShareDB;Data Source=Queen;User ID=sa;Password=mypassword

Queen SQL Server security: SQL Server and Windows Authentication mode

Project with c#


Project with c#

Project Name:BdcSharp

SQL Server Security: Windows Authentication mode

SQL server connection string

Initial Catalog=ShareDB;Data Source=Queen;Integrated Security=SSPI

Impersonate user

Impersonate user sam


Retrieve Username and Password from Secure Store Service

Because the Target Application ID is SINGLE type, only the Credential Owner:aaa\administrator and Windows user:Nicole can access the Target Application ID:QueenID.

I will not use aaa\nicole as Windows User Name. Instead Nicole is typed in. The domain name is hard-coded in the follow program.

08

Project Name: BdcSharp

Impersonate Username Retrieved from Secure Store Service


Impersonate a user class


 

using System;

using System.Runtime.InteropServices;

using System.Security.Principal;

public class Impersonate : IDisposable

{

public const int LOGON32_LOGON_INTERACTIVE = 2;

public const int LOGON32_PROVIDER_DEFAULT = 0;



WindowsImpersonationContext impersonationContext;



public Impersonate()

{

//Default login is used.

this.impersonateValidUser("administrator", "aaa", "Vista2006");

}



public Impersonate(string username, string domain, string password)

{

this.impersonateValidUser(username, domain, password);

}



[DllImport("advapi32.dll")]

private static extern int LogonUserA(String lpszUserName,

String lpszDomain,

String lpszPassword,

int dwLogonType,

int dwLogonProvider,

ref IntPtr phToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

private static extern int DuplicateToken(IntPtr hToken,

int impersonationLevel,

ref IntPtr hNewToken);



[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

private static extern bool RevertToSelf();



[DllImport("kernel32.dll", CharSet = CharSet.Auto)]

private static extern bool CloseHandle(IntPtr handle);



private bool impersonateValidUser(string userName, string domain, string password)

{

WindowsIdentity tempWindowsIdentity;

IntPtr token = IntPtr.Zero;

IntPtr tokenDuplicate = IntPtr.Zero;



if (RevertToSelf())

{

if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,

LOGON32_PROVIDER_DEFAULT, ref token) != 0)

{

if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)

{

tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);

impersonationContext = tempWindowsIdentity.Impersonate();

if (impersonationContext != null)

{

CloseHandle(token);

CloseHandle(tokenDuplicate);

return true;

}

}

}

}

if (token != IntPtr.Zero)

CloseHandle(token);

if (tokenDuplicate != IntPtr.Zero)

CloseHandle(tokenDuplicate);

return false;

}



private void undoImpersonation()

{

impersonationContext.Undo();

}



public void Dispose()

{

Dispose(true);

GC.SuppressFinalize(this);

}



~Impersonate()

{

Dispose(false);

}



protected virtual void Dispose(bool disposing)

{

if(disposing)

{

//Dispose of managed resources.

if(impersonationContext != null)

{

this.undoImpersonation();

impersonationContext.Dispose();

impersonationContext = null;

}

}

}

}


Retrieve Username and Password from Secure Store Service


using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using Microsoft.BusinessData.Infrastructure.SecureStore;
using Microsoft.Office.SecureStoreService.Server;
using Microsoft.SharePoint;

public static class SecureStoreUtils
{
public static Dictionary<string, string> GetCredentials(string applicationID)
{
var serviceContext = SPServiceContext.Current;
var secureStoreProvider = new SecureStoreProvider { Context = serviceContext };
var credentialMap = new Dictionary<string, string>();

using (var credentials = secureStoreProvider.GetCredentials(applicationID))
{
var fields = secureStoreProvider.GetTargetApplicationFields(applicationID);
for (var i = 0; i < fields.Count; i++)
{
var field = fields[i];
var credential = credentials[i];
var decryptedCredential = ToClrString(credential.Credential);

credentialMap.Add(field.Name, decryptedCredential);
}
}

return credentialMap;
}

public static string ToClrString(this SecureString secureString)
{
var ptr = Marshal.SecureStringToBSTR(secureString);

try
{
return Marshal.PtrToStringBSTR(ptr);
}
finally
{
Marshal.FreeBSTR(ptr);
}
}
}


Using the above two classes


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualBasic;

using System.Collections;

using System.Data;
using System.Diagnostics;

using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;

namespace BdcSharp.BdcModel1
{
/// <summary>
/// All the methods for retrieving, updating and deleting data are implemented in this class file.
/// The samples below show the finder and specific finder method for Entity1.
/// </summary>
public class Entity1Service
{
private static SqlConnection getSqlConnection()
{

SqlConnection sqlConn = new SqlConnection("Initial Catalog=ShareDB;Data Source=Queen;Integrated Security=SSPI");
return (sqlConn);

}

public static Entity1 ReadItem(short id)
{

Dictionary<string, string> SSc = SecureStoreUtils.GetCredentials("QueenID");
string strUsername= SSc.ElementAt(0).Value;

string strPassword = SSc.ElementAt(1).Value;

using (var imp = new Impersonate(strUsername, "aaa", strPassword))
{

//TODO: This is just a sample. Replace this simple sample with valid code.
SqlConnection aConn = null;
Entity1 objCourse;
SqlDataReader aReader;
objCourse = new Entity1();
try
{

aConn = getSqlConnection();
aConn.Open();
SqlCommand aCmd = new SqlCommand();
aCmd.CommandText = "Select CourseID,CourseName,Description,Grade from Course Where CourseID= " + id.ToString();
aCmd.Connection = aConn;
aReader = aCmd.ExecuteReader(CommandBehavior.CloseConnection);
if (aReader.Read())
{
objCourse.CourseID = id;
objCourse.CourseName = aReader[1].ToString();
objCourse.Description = aReader[2].ToString();
objCourse.Grade = decimal.Parse(aReader[3].ToString());
}
else
{
objCourse.CourseID = -1;
objCourse.CourseName = "Data Not Found";
objCourse.Description = "Data Not Found";
objCourse.Grade = 0;
}
aReader.Close();
return (objCourse);

}
catch (Exception ex)
{
objCourse.CourseID = -1;
objCourse.CourseName = "Data Not Found";
objCourse.Description = ex.ToString();
objCourse.Grade = 0;
return (objCourse);
}
finally
{
aConn.Dispose();
}

}
}

public static IEnumerable<Entity1> ReadList()
{

Dictionary<string, string> SSc = SecureStoreUtils.GetCredentials("QueenID");
string strUsername = SSc.ElementAt(0).Value;

string strPassword = SSc.ElementAt(1).Value;

using (var imp = new Impersonate(strUsername, "aaa", strPassword))
{

SqlConnection aConn = null;
List<Entity1> AllEntity1s = null;
SqlDataReader aReader;
try
{
aConn = getSqlConnection();
AllEntity1s = new List<Entity1>();
aConn.Open();
SqlCommand thisCmd = new SqlCommand();
thisCmd.Connection = aConn;
thisCmd.CommandText = "Select courseID,courseName,Description,grade from course";
aReader = thisCmd.ExecuteReader(CommandBehavior.CloseConnection);
while (aReader.Read())
{
Entity1 objEntity1 = new Entity1();
objEntity1.CourseID = short.Parse(aReader[0].ToString());
objEntity1.CourseName = aReader[1].ToString();
objEntity1.Description = aReader[2].ToString();
objEntity1.Grade = decimal.Parse(aReader[3].ToString());
AllEntity1s.Add(objEntity1);
}
aReader.Close();
Entity1[] Entity1List = new Entity1[AllEntity1s.Count];
for (int courseCounter = 0; courseCounter <= AllEntity1s.Count - 1; courseCounter++)
{
Entity1List[courseCounter] = AllEntity1s[courseCounter];
}
return (Entity1List);
}
catch (Exception ex)
{
Entity1[] errEntity1List = new Entity1[1];
Entity1 errCourse = new Entity1();
errCourse.CourseID = -1;
errCourse.CourseName = ex.Message;
errCourse.Description = ex.Message;
errCourse.Grade = 0;
errEntity1List[0] = errCourse;
return (errEntity1List);
}
finally
{
aConn.Dispose();
}

}
}

}
}


Properties of class Entity1


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BdcSharp.BdcModel1
{
/// <summary>
/// This class contains the properties for Entity1. The properties keep the data for Entity1.
/// If you want to rename the class, don't forget to rename the entity in the model xml as well.
/// </summary>
public partial class Entity1
{
private Int16 _CourseID;
private string _CourseName;
private string _Description;
private decimal _Grade;
public Int16 CourseID
{
get { return _CourseID; }
set { _CourseID = value; }
}
public string CourseName
{
get { return _CourseName; }
set { _CourseName = value; }
}
public string Description
{
get { return _Description; }
set { _Description = value; }
}
public decimal Grade
{
get { return _Grade; }
set { _Grade = value; }
}

}
}


Create Target Application ID:QueenID----Group type

09

10

11

The C# code:

12

13

The updated code is:

Impersonation and Retrieve credentials from SSS