Why does my tempdb reset permissions when the server is rebooted? - asp.net

The past two times we have rebooted our sql server, our website has gone down. The reason appears to be because the tempdb is getting recreated and the ASPState user is losing permission to read/write to the tempdb (it is an ASP site and session data is stored in the sql server)
This was not a problem until about two weeks ago. Does anyone know how I can prevent the sql server from resetting tempdb permissions after a reboot? Or why this only started happening recently? We are using MS SQL Server 2005.

First off, you shouldn't assign permissions to the tempdb directly. For the obvious reasons that it gets recreated on every reboot.
Which actually raises a question: why do you need to have direct permissions to this database anyway?
You don't need any permissions beyond just being able to connect to sql server in order to create temp tables. However, if you are creating real tables in the tempdb, then I highly suggest you change this to use a dedicated database for this purpose.
UPDATE
Based on Martin's comment all I can say is wow. I would never even have considered that this would have been an option.
Okay, now that I've recovered from the shock.
Create a new job in sql server that executes on a schedule. The schedule should be set to "Start Automatically whenever SQL Server Agent Starts". The job should recreate your necessary tempdb permissions.
In a nutshell, when the server is rebooted the SQL Server Agent will be restarted (provided the service is set that way). When it restarts it will kick off this job that will then fix your permissions. I'd expect the site to remain down for only a few seconds more than it takes for SQL server to completely restart.

I know this is an old question but found some new information regarding the tempdb behaviour on restarting.
The tempdb is essentially recreated from the 'model' db and that is the reason why all changes to it are lost. If you make a change to persist your changes even after restart make the same changes to the 'model' db as you would to the 'tempdb'.
Have a look at the following: Does tempdb Get Recreated From model at Startup?

The Model database is used as a template for TempDB. Add users and permissions to model and the same usere and permissions will be used on TempDB. I do not say that this is the optimal solution for every case but it worked for me in a situation where an application needed speciffic TempDB access.

Create a startup script on sql Server as below:
use master
go
drop proc AddAppTempDBOwner
go
create proc AddAppTempDBOwner as
declare #sql varchar(200)
select #sql = 'use tempdb' + char(13)
+ 'exec sp_addrolemember ''db_owner'', ''app'''
exec (#sql)
go
exec sp_procoption 'AddAppTempDBOwner', 'startup', 'true'
go

Here's a script to create a startup stored procedure, which loops over Logins and creates Users in tempdb as db_owner. This script does not have harcoded logins.
As a result even after SQL machine restarts all SQL logins will have privileges to access tempdb.
USE [master]
GO
IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = object_id(N'AddUsersToTempDb')
and OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
DROP PROCEDURE AddUsersToTempDb
END
GO
CREATE PROCEDURE AddUsersToTempDb
AS
DECLARE #loginname as NVARCHAR(100);
DECLARE Login_Cursor CURSOR FOR
SELECT loginname
FROM master..syslogins
OPEN Login_Cursor;
FETCH NEXT FROM Login_Cursor INTO #loginname;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#loginname <> 'sa' AND (NOT #loginname LIKE '##%') AND (NOT #loginname LIKE '%\%'))
BEGIN
PRINT #loginname
IF EXISTS(SELECT * FROM [tempdb].sys.database_principals WHERE type_desc = 'SQL_USER' AND name = #loginname)
PRINT ' - user already exists'
ELSE
BEGIN
PRINT ' - creating user'
DECLARE #Sql VARCHAR(MAX)
SET #Sql =
'USE Tempdb' + char(13) +
'CREATE USER ' + #loginname + ' FOR LOGIN ' + #loginname + char(13) +
'EXEC sp_addrolemember db_owner, ' + #loginname
EXEC (#Sql)
END
END
FETCH NEXT FROM Login_Cursor INTO #loginname;
END;
CLOSE Login_Cursor;
DEALLOCATE Login_Cursor;
GO
EXEC sp_procoption 'AddUsersToTempDb', 'startup', 'true'
GO

The tempdb database in SQL server is (from everything I've ever read, heard, or experienced) completely dropped and recreated every time the service is started up. Thus, anything stored within or written to that database, including roles, users, or other access right settings, will be wiped out. Barring some fussy code to set/reset them whenever the instance starts up, I don't think you can work around this. (I don't think anything set in the model database gets copied over to tempdb when it's created, but I've never even thought about that...)
Are any such settings being written to that databases? Are you sure that your system has not been recently changed or updated to do so? Possibly relevant, how often does the SQL instance get stopped and restarted? (It's not uncommon--if not wise--for SQL to run for months if not yers without a restart...)

Related

Provider 'MICROSOFT.ACE.OLEDB.12.0' has been denied when executing stored procedure from ASPX page

I've been looking all around for a fix, but I cannot find it.
Basically I setup a stored procedure in sql server that reads an excel file into a table. I managed to make it work inside SQL Server Management Studio. But when I try to execute it inside a webpage I get the error:
Ad hoc access to OLE DB provider 'MICROSOFT.ACE.OLEDB.12.0' has been
denied. You must access this provider through a linked server.
Things I've tried include running the following commands:
sp_configure 'Show Advanced Options', 1;
RECONFIGURE;
GO
sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
EXEC master . dbo. sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0' , N'AllowInProcess' , 1
GO
EXEC master . dbo. sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0' , N'DynamicParameters' , 1
GO
I've also tried giving access to the temp folder of SQL Server to my SQL user.
I've been running in circles for a while... here is the relevant SQL code that runs fine inside management studio:
set #q = 'INSERT INTO #RDV_BUFFER (noDossier,RDVDate,Facturation,debut,fin,debutreel,finreel,MinutesParUnites) SELECT nodos, daterdv, montfact, heuredebut, heurefin,heureassis,heureleve,horstep FROM OPENROWSET(''MICROSOFT.ACE.OLEDB.12.0'',''Excel 8.0; Database=C:\inetpub\wwwroot\ProDentaireElite\XLS_Root\' + #URL + '; HDR=YES; IMEX=1'', ''SELECT * FROM [' + #Sheetname + '$]'')'
EXEC sp_executesql #q
Thanks to all the gurus out there. Maybe your knowledge can help.
Ok I found it, there were 2 "Temp" folders I needed to give access to my SQL User. One located in the windows microsoft sql server folder, and the other, located in my own user. Make sure you set them up to ''Full control'' or it won't work.

SP Not Found When It Clearly Exists

I copied a database from a live MSSQL server to my local one, and was able to log in correctly. I am having a problem however in that when it is time to call a stored procedure the Asp.Net application keeps telling me the SP does not exist, when it clearly does.
I am using windows authentication but on the server I was using credentials, could this be the problem?
Also, all of the SP's have my online username attached to their name, as in username.StoredProcedurenName.
Please help I have been trying to fix this for hours.
I just noticed that when I attempt to run the SP from the SQL Management Studio it works, but it appends the username to the SP such as:
USE [DBNAME]
GO
DECLARE #return_value int
EXEC #return_value = [username].[SPNAME]
SELECT 'Return Value' = #return_value
GO
If I remove the username, it says the same thing (SP not found). How do I get around this?
I suspect you are calling your stored procedure without specifying the schema. When calling a stored procedure (or accessing a table, view, etc) that's not in the default schema that your account is configured for, usually dbo, you need to explicitly include the schema like the sql command below
SqlCommand cmd = new SqlCommand("username.StoredProcedurenName", mySqlConnection);
It's likely what Jason said. The solution has to do with rights and ownership. When you see the SP in the SQL Management Studio, under Programmability->Stored Procedures, your SP should have a prefix like "dbo." or "GateKeeper."
If the SP has "dbo." as the prefix, the user account with which you're connecting to the DB just be part of the database owners (dbo) group, otherwise you won't have access to it. So, you can either add the user to that group, or create the stored procedure ("create procedure spBlahBlah as ..") using the account to plan to run the program under; when you call it you use "exec GateKeeper.spBlahBlah" to stipulate the Schema.StoredProcedureName.
Those are your two choices.

Is possible to clone SQL database from ASP.Net application efficiently?

There are a lot of database cloning tools out there such as SQL Data Compare.
However, end users (using ASP.Net Application) want to clone the staging SQL Server 2008 database to production SQL Azure database himself when contents is ready.
I'm sure that I can compare each and every table using Entity Framework, and insert/update/delete each row. Is there any better method?
Thank you for your help!
You could use the different classes in the Microsoft.SqlServer.Management namespace to manage all aspects of SQL Server.
This includes doing a backup from one server and restore into another (including changing logfile names and whatever else is needed).
In essence, if you can do it in SSMS, you can use these classes to do the same.
I have used this in the past do do something close to what you are describing.
Why not backup the database and restore it?
You can run a backup and restore from your web application without much difficulty. You should probably write the code to handle the backup in a stored procedure instead of trying to write the logic in your application code. Something like:
CREATE PROCEDURE dbo.InitiateClone
#DBName SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'BACKUP DATABASE ' + QUOTENAME(#DBName)
+ ' TO DISK = ''\\Common_network_path\wherever\' + #DBName + '.BAK''
+ WITH INIT;';
EXEC sp_executesql #sql;
SET #sql = N'SELECT name, type_desc FROM sys.
END
GO
Now the app that asks for the backup can consume the data and log file name to pass to the procedure on the other server:
CREATE PROCEDURE dbo.FinishClone
#NewDBName SYSNAME,
#OldDBName SYSNAME,
#DataFileName VARCHAR(255),
#LogFileName VARCHAR(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'RESTORE DATABASE ' + QUOTENAME(#NewDBName)
+ ' FROM DISK = ''\\Common_network_path\wherever\' + #OldDBName + '.BAK''
+ ' WITH MOVE ''' + #DataFileName + ''' TO ''D:\datapath\'
+ #NewDBName + '_data.mdf'','
+ ' MOVE ''' + #LogFileName + ''' TO ''D:\logpath\'
+ #NewDBName + '_log.ldf'';';
EXEC sp_executesql #sql;
END
GO
The only thing you need to worry about is if two users try to clone the same source database at the same time, so you may want to put some kind of queuing or semaphore control in there. I also omitted error handling for brevity (e.g. making sure the new name doesn't already exist). It also assumes you have simple databases (one data file and one log file). But it's a start.
EDIT since we know the destination is Azure:
With Azure I think your options are limited. I don't think you can perform a restore this way. How are you going to initiate the creation of the new database on Azure? Once that's done then you can still consider some of the third party tools for comparing and synchronizing. Red Gate's tools, for example, have command-line interfaces, which means you can certainly invoke them in response to requests from your web application.
Backing a database is a lot more difficult than reading tables and records. The sequence of the restore is critical, and so is the performance aspect of the restore operation to avoid throttling as much as possible.
You might be able to script a DACPAC operation; I am not sure how to do that, but it may be possible. The DACPAC is the official Microsoft solution for backing up and restoring databases. Here is a link to the DACPAC overview; you can probably find a way to use this programmatically: http://msdn.microsoft.com/en-us/library/dd193245.aspx
Using third party tools, the Enzo Backup tool will soon provide an API to backup/restore a database programmatically. The API will allow developers to start/stop/send alerts upon completion of database backup and restore operations against a SQL Azure database (limited support for SQL Server). The API is available upon private request at this point; please contact info#bluesyntax.net for information about the API if you decide to give it a try.
[DISCLAIMER: I am the author of the backup tool]

Adding tempdb items on startup in SQL Server

How could I add some items to the tempdb anytime SQL Server starts up?
I'm no expert at this, but our ASP SessionState is stored in the DB and for some reason the tempdb items used for the session state get dropped anytime the server restarts. Not only do I need to recreate the items, but I also have to recreate the User mappings to tempdb. I have a script that does it, but I can't figure out how to run it on SQL startup
-- Use TempDB
use tempdb
go
-- Create Temp tables if they don't exist
IF NOT EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_NAME = 'ASPStateTempSessions')
BEGIN
EXECUTE [ASPState].[dbo].[CreateTempTables]
END
-- If ASPSessionState user isn't mapped to temp db, map it
IF IS_MEMBER('ASPSessionState') IS NULL
create user ASPSessionState from login ASPSessionState
-- Give ASPSessionState user read/write permissions to tempdb
exec sp_addrolemember db_datareader, ASPSessionState
go
exec sp_addrolemember db_datawriter , ASPSessionState
go
Um, if you've used the standard settings to enable ASP.Net session state in tempdb, the system should have generated a stored proc (ASPState_Startup) as follows in the master database. This stored proc is configured to run automatically on SQL Server startup:
USE master
GO
DECLARE #sstype nvarchar(128)
SET #sstype = N'sstype_temp'
IF UPPER(#sstype) = 'SSTYPE_TEMP' BEGIN
DECLARE #cmd nchar(4000)
SET #cmd = N'
/* Create the startup procedure */
CREATE PROCEDURE dbo.ASPState_Startup
AS
EXECUTE ASPState.dbo.CreateTempTables
RETURN 0'
EXEC(#cmd)
EXECUTE sp_procoption #ProcName='dbo.ASPState_Startup', #OptionName='startup', #OptionValue='true'
END
So, the temp tables should be being recreated anyway, unless something has been altered since installing.
If additional permissions are required, I'd look to extending the existing CreateTempTables procedure in ASPState.
If this isn't working correctly, you might try using the aspnet_regsql command (found under %Windir%\Microsoft.Net\Framework\<framework version - to remove then re-add session state support to the server. You'd want to use -ssremove then -ssadd, but I'd suggest passing /? first to see all of the applicable options.

Automatic fix for tempdb error related to 'ASPStateTempSessions'

As per this how-to, I've successfully configured IIS on my XP-SP3 dev box for SQL Server 2008 Express to save ASP.NET session state information. I'm just using SQL Server because otherwise on every recompile, I was losing the session state which was obnoxious (having to re-login). But, I'm facing an annoying issue in that every time I restart SQL there's this error, and sometimes one or two other very similar friends:
The SELECT permission was denied on the object 'ASPStateTempSessions',
database 'tempdb', schema 'dbo'.
To fix the error, I just open Management Studio and edit the User Mapping for the login/dbo I'm using on the ASPState db, and re-add tempdb to that user with all but deny permissions. Apparently, once the right permissions are there, ASP.NET is able to automatically create the tables it uses. It just can't run that CreateTempTables sproc until the right security is there.
THE QUESTION...
Is there a way to not have to re-do this on every restart of the SQL Server?
I don't really care right now about keeping the temp data across restarts, but I would like to not have to go through this manual step just to get my web app working on localhost, which uses session state variables throughout. I suppose one could resort to some kind of stored procedure within SQL Server to accomplish the task for this machine when the service starts, to not have to do it manually. I'd accept such an answer as a quick fix. But, I'm also assuming there's a better recommended configuration or something. Not seeing an answer to this on the how-to guide or elsewhere here on StackOverflow.
Both answers seem valid; but with most things Microsoft, its all in the setup...
First uninstall the ASPState database by using the command:
aspnet_regsql –ssremove –E -S .
Note:
-E is to indicate you want to use integrated security connection.
-S informs what SQL server and SQL instance to use, and the "." (dot) specifies default local instance
Then re-install using the command:
aspnet_regsql –ssadd –sstype p –E -S .
Note:
The sstype has three options, t | p | c ... the first "t", tells the installer to host all stored procedures in the ASPState database, and all data in the tempdb. The second option "p" tells the installer to persist data to the ASPState database. The last option "c" allows you to specify a different 'custom' database to persist the session state data.
If you reinstall using the "-sstype p" you then need only to supply datareader/datawriter to the ASPState database for the user that's making the connection (in most cases, the application pool's identity in IIS).
The added benefit of persisting the data is that session state is retained even after a restart of the service. The only drawback is that you need to ensure the agent cleanup job is pruning old sessions regularly (it does this by default, every minute).
Important:
If you are running a cluster, you must persist session data. You're only option is to use sstype 'p' or 'c'.
Hope this sheds light on the issue!
For the record, I did find a way to do this.
The issue is that the tempdb is recreated from the model db each time the service restarts. The gist of the solution is to create a stored procedure that does the job, and then make that procedure run at startup.
Source code (credit to the link above) is as follows:
use master
go
-- remove an old version
drop proc AddAppTempDBOwner
go
-- the sp
create proc AddAppTempDBOwner as
declare #sql varchar(200)
select #sql = 'use tempdb' + char(13) + 'exec sp_addrolemember ''db_owner'', ''app'''
exec (#sql)
go
-- add it to the startup
exec sp_procoption 'AddAppTempDBOwner', 'startup', 'true'
go
Well done for finding the strangest way possible to do this.
The correct answer is as follows:
use master
go
EXEC sp_configure 'Cross DB Ownership Chaining', '1'
go
RECONFIGURE
go
EXEC sp_dboption 'ASPState', 'db chaining', 'true'
go

Resources