Restore network database on SQL Server without copy it - c#

I trying to restore a SQL Server backup over the network.
I found a lot of way to copy file over network but backup files are big I don't want to copy them.
My problem is simple: this line
var fileList = restore.ReadFileList(smoServer);
executes on SQL Server.
This one define the backup I try to restore
var backupDeviceItem = new BackupDeviceItem(path, DeviceType.File);
The problem is the path looks like: 10.\*.\*.\*\\file.bak
So I get an exception that says
"10.*.*.*" path not found on server
That is logical - I need to provide credential for the machine 10.\*.\*.\*
If path parameter is C:\file.bak, my code works - if it's \\10.\*.\*.\*\\file.bak, my code says "file not found".
The BackupDeviceItem has a constructor with credentials but its SQL credential... or I'm already on my SQL Server... I need credentials for the machine that has the .bak file ...
Any ideas?
Just in case someone want my entire code here is my helper
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using System;
using System.IO;
namespace SqlManager.Tools
{
public class SMOHelper
{
public static void RestoreDatabase(string path, string restore_name, SqlConfig sqlAccess)
{
ServerConnection SqlConnection;
if (String.IsNullOrWhiteSpace(sqlAccess.username))
{
SqlConnection = new ServerConnection(sqlAccess.uri);
}
else
{
SqlConnection = new ServerConnection(sqlAccess.uri, sqlAccess.username, sqlAccess.password);
}
Server smoServer = new Server(SqlConnection);
try
{
// On crée la BDD
if (!smoServer.Databases.Contains(restore_name))
{
Logger.Info("Creation de la base:");
Logger.Info(restore_name);
var database = new Database(smoServer, restore_name);
database.Create();
}
Logger.Success("Connexion SQL réussi");
var targetDatabase = smoServer.Databases[restore_name];
targetDatabase.RecoveryModel = RecoveryModel.Simple;
targetDatabase.Alter();
Restore restore = new Restore();
var backupDeviceItem = new BackupDeviceItem(path, DeviceType.File);
restore.Devices.Add(backupDeviceItem);
restore.Database = restore_name;
restore.ReplaceDatabase = true;
restore.NoRecovery = false;
restore.Action = RestoreActionType.Database;
var fileList = restore.ReadFileList(smoServer);
Logger.Success("Fichier de backup trouvé sur le serveur distant");
var dataFile = new RelocateFile();
dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
dataFile.PhysicalFileName = smoServer.Databases[restore_name].FileGroups[0].Files[0].FileName;
var logFile = new RelocateFile();
logFile.LogicalFileName = fileList.Rows[1][0].ToString();
logFile.PhysicalFileName = smoServer.Databases[restore_name].LogFiles[0].FileName;
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
var backupHeaderInfo = restore.ReadBackupHeader(smoServer);
smoServer.KillAllProcesses(restore_name);
Logger.Info("Debut de la restauration sur le server");
restore.SqlRestore(smoServer);
Logger.Success("Restauration terminer");
targetDatabase.SetOnline();
SqlConnection.Disconnect();
}
catch (SmoException ex)
{
Logger.Error("SMO Message : " + ex.Message);
Logger.Error("SMO Exception : " + ex.InnerException);
}
catch (IOException ex)
{
Logger.Error("IO Message : " + ex.Message);
Logger.Error("IO Exception : " + ex.InnerException);
}
catch (Exception ex)
{
Logger.Error("Message : " + ex.Message);
Logger.Error("Exception : " + ex.InnerException);
}
}
}
}

You say
So i get an exception that say "10.*.*.*" path not found on server
You cannot use an asterisk in a folder name or a file name on a Windows server. See Naming Files, Paths, and Namespaces

Related

Running a command although the connection is close adomd

I have read the Mirosoft Document.When we open a connection and then close it, it is possible to use the session.
I have written this block of code to run a command but I get an error message, which says there is no connection. Do you have any Idee how can I close the connection, but use the session to run a cammand:
try
{
using (AdomdConnection adomdConnection = new AdomdConnection("MY Connection String"))
{
adomdConnection.Open();
adomdConnection.Close(false);
while (true)
{
String query = #"EVALUATE { BLANK()}";
AdomdCommand adomdCommand = new AdomdCommand(query);
Console.WriteLine(adomdConnection.SessionID.ToString() + " " + DateTime.Now.ToString());
AdomdDataReader reader = adomdCommand.ExecuteReader();
reader.Close();
System.Threading.Thread.Sleep(30000);
}
}
}
catch(AdomdConnectionException ex)
{
Console.WriteLine(ex.Message.ToString());
}
In the examples shown in the document you list, it has:
/*First, try to connect to the specified data source.
If the connection string is not valid, or if the specified
provider does not support sessions, an exception is thrown. */
objConnection.ConnectionString = connectionString;
objConnection.Open();
// Now that the connection is open, retrieve the new
// active session ID.
strSessionID = objConnection.SessionID;
// Close the connection, but leave the session open.
objConnection.Close(false);
return strSessionID;
And in your code specifically, you have:
adomdConnection.Open();
adomdConnection.Close(false);
while (true)
{
String query = #"EVALUATE { BLANK()}";
AdomdCommand adomdCommand = new AdomdCommand(query);
Console.WriteLine(adomdConnection.SessionID.ToString() + " " +
DateTime.Now.ToString());
AdomdDataReader reader = adomdCommand.ExecuteReader();
reader.Close();
System.Threading.Thread.Sleep(30000);
}
Wouldn't you want to have this instead (based on the example given)?
adomdConnection.Open();
while (true)
{
String query = #"EVALUATE { BLANK()}";
AdomdCommand adomdCommand = new AdomdCommand(query);
Console.WriteLine(adomdConnection.SessionID.ToString() + " " +
DateTime.Now.ToString());
AdomdDataReader reader = adomdCommand.ExecuteReader();
reader.Close();
System.Threading.Thread.Sleep(30000);
}
adomdConnection.Close(false);
It seems as though it's complaining because you're closing the connection before you even use it, according to the order in which your code looks to be operating. Try moving the adomdConnection.Close(false); after your while loop.

connect to ssas via a web service asmx

hello people i don't know if i am askin properly but i have a big probleme i am new in programming i hope u can help me.
i created an asmx that execute a xmla query on analysis services so evrything is runing perfect when i try it in local but when i deployed on iis in a windows server 2008 r2 and i tested it generated me an error "A connection cannot be made. Ensure that the server is running" can you please guys help me with that i will appreciat it.
"Sorry if my english is bad".
[SoapRpcMethod()]
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String StartJob(String JobId)
{
string res = "";
string chronomark = (DateTime.Now).ToString("yyy-MM-dd_HHmmss");
String logFile = System.Configuration.ConfigurationManager.AppSettings["log"] + (JobId != null ? JobId : "null") + chronomark + ".log";
try
{
FileStream fs = new FileStream(logFile, FileMode.CreateNew);
StreamWriter swr = new StreamWriter(fs);
try
{
try
{
if (JobId == null) throw new Exception("NO JOB ID GIVEN");
Regex rgx = new Regex("^[0-9A-Z-]{32}$");
if (!rgx.IsMatch(JobId)) throw new Exception("BAD JOB ID");
MatchCollection mcol = rgx.Matches(JobId);
if (mcol.Count != 1) throw new Exception("BAD JOB ID Collection");
String sJobID = mcol[0].Value;
FileInfo fi = new FileInfo(System.Configuration.ConfigurationManager.AppSettings["storage"] + sJobID + ".cube");
if (!fi.Exists)
throw new Exception("NO REGISTRED JOB ID");
FileStream fstr;
try
{
fstr = fi.OpenRead();
}
catch (Exception ex)
{
swr.WriteLine(ex.ToString());
swr.WriteLine(ex.StackTrace);
throw new Exception("NO JOB ID REGISTRED");
}
StreamReader sr = new StreamReader(fstr);
String sTargetServer = sr.ReadLine();
StringBuilder sbrXMLA = new StringBuilder();
sbrXMLA.Append(sr.ReadToEnd());
sr.Close();
fstr.Close();
swr.WriteLine(sbrXMLA.ToString());
swr.WriteLine(sTargetServer);
res = sendXMLARequest(sbrXMLA.ToString(), sTargetServer, swr);
return res;
}
catch (Exception se)
{
swr.WriteLine(se.ToString());
swr.WriteLine(se.StackTrace);
res = "ERROR :" + se.Message.ToString();
return res;
}
}
finally
{
swr.Flush();
fs.Close();
}
}
catch(Exception exp)
{
res = "ERROR : " + exp.Message;
return res;
}
}
[WebMethod]
private String sendXMLARequest(String sXMLARequest, String sTargetServer, StreamWriter logger)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(sXMLARequest);
String Json = JsonConvert.SerializeXmlNode(doc);
Server server = new Server();
server.Connect(#"Provider=OLAP;Data Source=" + sTargetServer);
server.Execute(sXMLARequest);
string con = server.Connected.ToString();
XmlaResultCollection rsCollection = server.Execute(sXMLARequest);
String s = null;
foreach (XmlaResult res in rsCollection)
{
s += res.Value.ToString();
foreach (XmlaMessage message in res.Messages)
{
logger.WriteLine(message.ToString());
if (message is XmlaError)
Json = s + "ERROR : " + message.Description;
else
Json = s + "WARNIN : " + message.Description;
}
}
server.Disconnect();
JavaScriptSerializer js = new JavaScriptSerializer();
return js.Serialize(Json);
}
A possible reason: Lack of access to the IIS process to the SSAS server.
(1) Determine you IIS application pool identity
(2) Give permission to this user in SSAS
Additionally:
(1) How is your web service call authenticated (anonymous / windows authentication / etc) ?
(2) Look at the msmdsrv.log file in SSAS folder
See whether this related SO post helps:
Either the user, 'IIS APPPOOL\App Name', does not have access to the 'SSAS Cube Name' database, or the database does not exist

Backup and restore Azure database programmatically with smo

We have a running web application. Everything is hosted on azure.
We have one sql server and two databases: production and test.
Client requested functionality to backup production db and restore it in place of test db. I am using following code:
public static void BackupDatabase(string databaseName, string userName, string password, string serverName, string destinationPath)
{
try
{
Backup sqlBackup = new Backup();
sqlBackup.Action = BackupActionType.Database;
sqlBackup.BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString();
sqlBackup.BackupSetName = "Archive";
sqlBackup.Database = databaseName;
BackupDeviceItem deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
ServerConnection connection = new ServerConnection(serverName, userName, password);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[databaseName];
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
}
catch (FailedOperationException ex)
{
throw;
}
catch(ConnectionFailureException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
}
public static void RestoreDatabase(string databaseName, string filePath, string serverName, string userName, string password, string dataFilePath, string logFilePath)
{
try
{
Restore sqlRestore = new Restore();
BackupDeviceItem deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = databaseName;
ServerConnection connection = new ServerConnection(serverName, userName, password);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[databaseName];
db.Drop();
sqlRestore.Action = RestoreActionType.Database;
string dataFileLocation = dataFilePath + databaseName + ".mdf";
string logFileLocation = logFilePath + databaseName + "_Log.ldf";
db = sqlServer.Databases[databaseName];
RelocateFile rf = new RelocateFile(databaseName, dataFileLocation);
System.Data.DataTable logicalRestoreFiles = sqlRestore.ReadFileList(sqlServer);
sqlRestore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[0][0].ToString(), dataFileLocation));
sqlRestore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[1][0].ToString(), logFileLocation));
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[databaseName];
db.SetOnline();
sqlServer.Refresh();
}
catch(ExecutionFailureException ex)
{
throw;
}
}
Everything works locally and on all virtual machines. But now we have everything on Azure and I have no idea what backup directory should I set. It must be directory on server to which sqlclient (probably azure sql client) has access. Same thing goes when it comes to provide location during restoring database to test database.
How to get access to directories where backup can be stored and where mdf and log files can be saved?
Kind regards

Can't restore a .bak file to a database

I have successfully restored a database using smo restore method. But when I try to restore the same .bak file to another database it returns an exception as seen below
I have created the .bak file from a database template I used which is GC_BranchName. GC_Muntinlupa is the first database I have created and restored the .bak file on to it successfully. Can anyone advise me on this?
Here is my restore code:
bool RestoreDB(string name)
{
try
{
var connection = new ServerConnection(Properties.Settings.Default.Well);
var sqlServer = new Server(connection);
var rstDatabase = new Restore();
rstDatabase.Database = name;
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Devices.AddDevice(System.Environment.CurrentDirectory + "\\GC.bak", DeviceType.File);
rstDatabase.ReplaceDatabase = true;
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
return true;
}
catch (Exception ex)
{
MessageBox.Show("A problem occured when building the branch!" + ex, "Monytron Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
Sorry J.P Masangcay but i didn't had time to put it all together for you until now.
Here is the solution that works for you, verified by me.
Your problem is that you have file conficts if you restore your database backup to a new database.
Why file conflicts?
The default behavior of SQL Server is to restore the database using file paths and names for data and log files as they have been at the time of the backup. Therefore, if that originating database exists at the time of the restore process this leads to filesystem conflicts. They same conflict arises if you restore your database backup template to another server multiple times.
Your Case:
Database: GC_BranchName
Data File: GC_BranchName.mdf
Log File: GC_BranchName_log.ldf
Resore Database: GC_Muntinlupa
Data File: GC_BranchName.mdf
Log File: GC_BranchName_log.ldf
To solve the proplem you have to relocate files to have distinct filenames for your databases. Here is a solution, which simply adds/prepends the "new database name" to all files. This relocating under the hood restores the database using the TSQL "RESTORE DATABASE ... WITH MOVE" option, as your exception above is suggesting.
Resore Database: GC_Muntinlupa
Data File: GC_Muntinlupa_GC_BranchName.mdf
Log File: GC_Muntinlupa_GC_BranchName_log.ldf
bool RestoreDB(string name)
{
try
{
var connection = ServerConnection(Properties.Settings.Default.Well);
var sqlServer = new Server(connection);
var rstDatabase = new Restore();
rstDatabase.Database = name;
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Devices.AddDevice(System.Environment.CurrentDirectory + "\\GC.bak", DeviceType.File);
rstDatabase.ReplaceDatabase = true;
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
// move/rename physical filename by prepending database name to prevent FileSystem conflicts
var physicalName = r["PhysicalName"].ToString();
var path = System.IO.Path.GetDirectoryName(physicalName);
var filename = System.IO.Path.GetFileName(physicalName);
physicalName = System.IO.Path.Combine(path, string.Format("{0}_{1}", name, filename));
relocateFile.PhysicalFileName = physicalName;
rstDatabase.RelocateFiles.Add(relocateFile);
}
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
return true;
}
catch (Exception ex)
{
MessageBox.Show("A problem occured when building the branch!" + ex, "Monytron Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
This should solve the issue
namespace DB_Restore
{
class Program
{
static void Main(string[] args)
{
RestoreDatabase();
}
public static void RestoreDatabase()
{
try
{
ServerConnection connection = new ServerConnection(#"Server\instance", "uname", "PWD");
Server sqlServer = new Server(connection);
Restore rstDatabase = new Restore();
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Database = "H5MI_Automation_Restore_Backup";
BackupDeviceItem bkpDevice = new BackupDeviceItem(#"E:\DATA\QA_SP\MSSQL11.QA_SP\MSSQL\Backup\H5MI_Automation.bak", DeviceType.File);
rstDatabase.Devices.Add(bkpDevice);
rstDatabase.ReplaceDatabase = true;
//As mentioned in the above solution this code will take care .mdf and .ldf file location issue
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
Console.WriteLine(relocateFile.LogicalFileName);
var physicalName = r["PhysicalName"].ToString();
Console.WriteLine(physicalName);
var path = System.IO.Path.GetDirectoryName(physicalName);
Console.WriteLine(path);
var filename = System.IO.Path.GetFileName(physicalName);
Console.WriteLine(filename);
physicalName = path + #"\H5MI_Automation_Restore_Backup_" + filename;
Console.WriteLine(physicalName);
relocateFile.PhysicalFileName = physicalName;
Console.WriteLine(relocateFile.PhysicalFileName);
Console.WriteLine(relocateFile);
rstDatabase.RelocateFiles.Add(relocateFile);
}
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
}
catch (Exception e)
{
Console.Write(e);
}
}
}
}
Add the explanation of the code. Essentially the issue in the above-attached screenshot is because of the .mdf and .ldf file location. When you try to manually restore the DB u will also face the same issue. attaching the screenshot.Manual DB restore
Why its throwing error?
Its because the file is used by the actual DB(from where .bak file is genrated)
So, this piece of code will help you to change the location of both .mdf and .ldf file path.
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
Console.WriteLine(relocateFile.LogicalFileName);
var physicalName = r["PhysicalName"].ToString();
Console.WriteLine(physicalName);
var path = System.IO.Path.GetDirectoryName(physicalName);
Console.WriteLine(path);
var filename = System.IO.Path.GetFileName(physicalName);
Console.WriteLine(filename);
physicalName = path + #"\H5MI_Automation_Restore_Backup_" + filename;
Console.WriteLine(physicalName);
relocateFile.PhysicalFileName = physicalName;
Console.WriteLine(relocateFile.PhysicalFileName);
Console.WriteLine(relocateFile);
rstDatabase.RelocateFiles.Add(relocateFile);
}

BackupDevice.PhysicalLocation does not add to specified location

Using C# and SMO, when I create backups they are being copied to the default backup location used by SQL Server (C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\Backup), instead of the physical location that I specify in code:
Database database = Server.Databases[dbName]);
Backup backup = new Backup();
device = new BackupDevice();
device.Parent = Server;
device.Name = dbName + ".bak";
device.BackupDeviceType = BackupDeviceType.Disk;
device.PhysicalLocation = Path.Combine(filePath + device.Name); // doesn't appear to do anything
device.Create();
backup.Action = BackupActionType.Database;
backup.Database = database.Name;
backup.Devices.AddDevice(filePath, DeviceType.File);
backup.SqlBackup(server);
When I run my code, I find that the path that I specified ("C:\backupTest") is empty and the backup has been added to the default backup location.
Anyone know why this is?
try with below code
static void BackupDataBase(string databaseName, string destinationPath)
{
try
{
Server myServer = GetServer();
Backup backup = new Backup();
backup.Action = BackupActionType.Database;
backup.Database = databaseName;
destinationPath = System.IO.Path.Combine(destinationPath, databaseName + ".bak");
backup.Devices.Add(new BackupDeviceItem(destinationPath, DeviceType.File));
backup.Initialize = true;
backup.Checksum = true;
backup.ContinueAfterError = true;
backup.Incremental = false;
backup.LogTruncation = BackupTruncateLogType.Truncate;
backup.SqlBackup(myServer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static Server GetServer()
{
ServerConnection conn = new ServerConnection("server", "username", "pw");
Server myServer = new Server(conn);
return myServer;
}
refere this codeproject article for more information.

Categories

Resources