: : Tom Fury
Den enda dokumentationen över Tommies liv

Database connection is working on the TFS now

Category: By Tom Fury

FINALLY! After too many hours of work I've finally got it working. Let me just summarize what I've done.

First of all I downloaded and installed the SQL Server Management Studio Express so I won't need to use a command line tool on my local computer. A very good tool for configuring your SQL server. What I did was to detach the database from my Solution in Visual Studio and saved it somewhere else (D:\CodeMetricsDB.mdf & D:\CodeMetricsDB_log.ldf) - this was because I couldn't add files located in my user account directory into the Management studio (I wonder why?).

Anyway. After opening the application and connecting to your SQL serve, right-clikc Databases --> Attach... --> Add... --> Select the D:\CodeMetricsDB.mdf file and then press OK. Congrats, you have your CodeMetricsDB in your SQL Server now. (I renamed it to CMDB in this case afterwards).

In Visual Studio, open the Server Explorer and right-click on the Data Connections symbol --> Add new connection... --> choose your server name and then choose the DB from "Select or enter a database name:" (in this case CMDB). Press OK.

Now you're set to develop against a database in your SQL server instead of a separate file located in the App_Data subfolder (which is troublesome when moving it to the VPC).

You can from inside SQL Server Management Studio Express generate a script which creates the database with all constraints, stored procedure etc. Do this and run the script on the VPC, or copy over the files (.mdf and .ldf) and then run this from a command line (found the tip here):

sqlcmd -E -Q "exec sp_attach_db @dbname=N'CMDB',
@filename1=N'C:\path\CodeMetricsDB.mdf',
@filename2
=N'C:\path\CodeMetricsDB_log.ldf'"

Now you should have the database in you VPC SQL Server (check it by either download and install SQL Server Management Studio Express on the VPC (yes, it works fine for "regular" SQL Server too), or use sqlcmd like this):

C:\> sqlcmd
1> use CMDB
2> go
Changed database context to
'CMDB'
1>

If it works, you have the database. Or, you could use a stored procedure to list the databases:

C:\>sqlcmd
1> sp_databases
2> go
DATABASE_NAME
---------------------------------------
---------------------------------------
CMDB

master

model

msdb

ReportServer

ReportServerTempDB

tempdb

TfsActivityLogging

TfsBuild

TfsIntegration

TfsWarehouse

TfsVersionControl

TfsWorkItemTracking

TfsWorkItemTrackingAttachments

WSS_AdminContent

WSS_Config

WSS_Content

1>

As you can see the CMDB database is on top.

But it isn't all set and done by just adding the table. Secondly you'll have to alter the connection string to:

1 string connstring = "Data Source=ORCASBETA2_TFSV;" +
2 "Database=CMDB;" +
3 "Integrated Security=true;";

As you can see we've changed the "Data source" from .\\SQLEXPRESS --> ORCASBETA2_TFSV (line 1) and the database name must match (line 2). Another thing to think about is if it is preferred to use SQL Server Authentication or Windows NT Authentication. We don't know yet, but probably Mr. König can give us some guidance of what method to prefer (as of now, I've just used Windows NT Authentication).

So everything should work fine now, right? No. When trying to access the database via the webservice by running the client on the VPC, we get an exception:

---------------------------

---------------------------
System.Data.SqlClient.SqlException: A connection was successfully established with the server, but then an error occurred during the login process.
(provider: Shared Memory Provider, error:
0 - No process is on the other end of the pipe.)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParserStateObject.ReadPacket(Int32 bytesExpected)
at System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
at System.Data.SqlClient.TdsParserStateObject.ReadByte()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject)
at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(String host, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, Int64 timerStart)
at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()
at CodeMetricsService.registerMetrics(Int32[] theMetrics, String projName)
in c:\WCFService1\App_Code\CodeMetricsService.cs:line 32
---------------------------
OK
---------------------------

After some googling and research, I finally found a solution to the problem. Here's how to get around:

  1. Start SQL Server Management Studio Express (in the VPC)
  2. Go to [your server] --> Security --> Logins in the left pane
  3. find NT AUTHORITY\NETWORK SERVICE and double click it to open the properties dialog
  4. Go to User Mappings in the left pane of the properties pane
  5. Identify your database in the table to the right (in this case: CMDB) and make sure the checkbox is marked under the column "Map" for you database
  6. Under "Database role memebership for: CMDB [you databasename] check "db_owner".
  7. Now it should work fine!

I don't know if this is a smart thing to do when havin security in mind, and there are possibly other combinations of role memberships that you could use to make it work (instead of db_owner). But it worked and I'm satisfied with that as for now. Improving things will be a later problem - now we can continue our work - and that would be to create an adapter for the TFS warehouse (finally!).

Oh yeah, and another thing. It isn't really working well to develop in the VPC using VS 2008. Everytim I try to build my solution for the website, it never finishes the build - just keeps on chewing on forever (even though it says "Validation Complete"). I don't know what's wrong and I don't have time to find out - so I will continue to develop on my XP machine and transfer files as necessary to the VPC via FTP.

Phew! That's a long post. Hope it could be helpful for someone out there.

0 comments so far.

Something to say?