First Process:
Get the column ip_address,subnet from database
I will set the column ip address to label1.text and subnet to label2.text
string connection = "Server=192.168.1.10;Database=xxxxx;User Id=xxxxx;Password=xxxxxx;";
try
{
SqlConnection conn = new SqlConnection(connection);
conn.Open();
var query = "SELECT TOP 1 ip_address,subnet,gateway FROM computer_info WHERE pc_name = HOST_NAME() ORDER BY id DESC";
SqlCommand cmd = new SqlCommand(query, conn);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
// column ip
string ip_address = dr["ip_address"].ToString();
string sub_net = dr["subnet"].ToString();
string gateway = dr["gateway"].ToString();
label1.Text = ip_address;
label2.Text = sub_net;
}
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Second Process:
I want to change my ip address and my subnet
Note: the value of ip address and subnet is from database
public void setIP(string ip_address, string subnet_mask)
{
ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection objMOC = objMC.GetInstances();
foreach (ManagementObject objMO in objMOC)
{
if ((bool)objMO["IPEnabled"])
{
try
{
ManagementBaseObject setIP;
ManagementBaseObject newIP =
objMO.GetMethodParameters("EnableStatic");
newIP["IPAddress"] = new string[] { ip_address };
newIP["SubnetMask"] = new string[] { subnet_mask };
setIP = objMO.InvokeMethod("EnableStatic", newIP, null);
}
catch (Exception)
{
throw;
}
}
}
}
Third process execute
Note: I have 2 example code here 1 is working and 2 not working
private void button1_Click_1(object sender, EventArgs e)
{
setIP(
// if i use this static string value my address is changing.
"192.168.1.5",
"255.255.255.0"
);
///---------------------------------------///////////////////////////////////////
setIP(
//the value inside of label1 , label2 is from database. ??? the question is why there is no result if the value came from the database.
label1.Text,
label2.Text
);
}
I hope you will help me guys.. thanks.
I would make sure my connection string is working. This the only thing I can see. Check while stepping through your code to see if you get a value back. Also make sure your router and modem have port forwarding on if you are trying to reach a database on your domain. However, if your trying to reach a server outside the network then I would definitely make sure you can reach the server by ping the server.
Easiest way to debug is to set BreakPoint at setIP function and view the value of label2.Text in "Immediate Window" [To open Immediate Window in VS menu : Debug -> Window -> Immediate Window]. Please confirm whether you are getting value here. If you are not getting value here, share your front-end label tag you have used.
Related
I am writing an application to make changes to network adapter IP address settings. Only the basic IP settings is what I will change from the application.
Is there any way for me to make use of some sort of "link" or "path" to open the "Advanced TCP/IP Settings" screen normally accessed VIA the "Advanced" button in the TCP/IPv4 Properties screen?
The above screen capture shows the highlighted button that would normally be used to open the advanced TCP/IP Settings screen. I need a way to open this exact screen from my application directly using a button.
You could do something like:
System.Diagnostics.Process.Start("ncpa.cpl"); // opens network connections window
Thread.Sleep(500); // give time for window to open
SendKeys.Send("(^a){RIGHT}(%f)r"); // select all (ctrl+a), right arrow, alt+f, r
You can set the IP address of a network adapter by using the following code
public void setIP(string IPAddress,string SubnetMask, string Gateway)
{
ManagementClass objMC = new ManagementClass(
"Win32_NetworkAdapterConfiguration");
ManagementObjectCollection objMOC = objMC.GetInstances();
foreach(ManagementObject objMO in objMOC)
{
if (!(bool) objMO["IPEnabled"])
continue;
try
{
ManagementBaseObject objNewIP = null;
ManagementBaseObject objSetIP = null;
ManagementBaseObject objNewGate = null;
objNewIP = objMO.GetMethodParameters("EnableStatic");
objNewGate = objMO.GetMethodParameters("SetGateways");
//Set DefaultGateway
objNewGate["DefaultIPGateway"] = new string[] {Gateway};
objNewGate["GatewayCostMetric"] = new int[] {1};
//Set IPAddress and Subnet Mask
objNewIP["IPAddress"] = new string[] {IPAddress};
objNewIP["SubnetMask"] = new string[] {SubnetMask};
objSetIP = objMO.InvokeMethod("EnableStatic",objNewIP,null);
objSetIP = objMO.InvokeMethod("SetGateways",objNewGate,null);
Console.WriteLine(
"Updated IPAddress, SubnetMask and Default Gateway!");
}
catch(Exception ex)
{
MessageBox.Show("Unable to Set IP : " + ex.Message); }
}
I need to create an application for monitoring SQL Server 2000 Agent Job status and info when Job occur same as show on Windows application event log. Now I connect to the database already via a connection string, but I don't know how to get the status and info from Job.
I need to show status and info on Textbox.
What do you suggestion how to do.
Developer tools :
MS SQL Sever 2000 SP4
MS Visual Studio 2008 (C#)
I am a rookie programmer.
i can do this already...
i select form table "Sysjobserver" in database "msdb" for read status, date, time of job that i want.
use this code
public void GetJobsAndStatus()
{
string sqlJobQuery = "select j.job_id, j.name, j.enabled, jh.run_status," +
" js.last_outcome_message, jh.run_date, jh.step_name, jh.run_time" +
" from sysjobs j left join sysjobhistory jh on (j.job_id = jh.job_id)" +
" left join sysjobservers js on (j.job_id = js.job_id)" +
" where jh.run_date = (select Max(run_date) from sysjobhistory)" +
" and jh.run_time = (select Max(run_time) from sysjobhistory)";
// create SQL connection and set up SQL Command for query
using (SqlConnection _con = new SqlConnection("server=10.15.13.70;database=msdb;user id=sa;pwd="))
using (SqlCommand _cmd = new SqlCommand(sqlJobQuery, _con))
{
try
{
// open connection
_con.Open();
SqlConnection.ClearPool(_con);
// create SQL Data Reader and grab data
using (SqlDataReader rdr = _cmd.ExecuteReader())
{
// as long as we get information from the reader
while (rdr.Read())
{
Guid jobID = rdr.GetGuid(0); // read Job_id
string jobName = rdr.GetString(1); // read Job name
byte jobEnabled = rdr.GetByte(2); // read Job enabled flag
int jobStatus = rdr.GetInt32(3); // read last_run_outcome from sysjobserver
string jobMessage = rdr.GetString(4); // read Message from sysjobserver
int jobRunDate = rdr.GetInt32(5); // read run_date from sysjobhistory
string jobStepName = rdr.GetString(6); // read StepName from sysjobhistory
int jobRunTime = rdr.GetInt32(7); // read run_time from sysjobhistory
String[] lviData = new String[] // ตัวแปรอะเรย์ชื่อ lviData
{
jobID.ToString(),
jobName.ToString(),
jobStepName.ToString(),
jobMessage.ToString(),
jobStatus.ToString(),
jobRunDate.ToString(),
jobRunTime.ToString(),
//jobEnabled.ToString(),
};
newData = lviData;
DisplayList(); // for display data on datagridview
}
rdr.Close();
}
}
thank you for everybody help very much. :-D
SQL stored procedures of queries don't give you any system data unless you have db_owner rights on the msdb system database, at lease in SQL Server 2008. Therefore mentioned methods normally don't work for applications where you want to show or manage jobs. However SMO namespace provides you with managed code solution for many SQL Server management features, including the SQL Server Agent functions that only require SQLServerAgent* permissions that you normally could get sorted for your application user. A good intro of using SMO classes to work with jobs is given here:
http://www.codeproject.com/Tips/367470/Manage-SQL-Server-Agent-Jobs-using-Csharp
I work on a similar task now and whilst SQL queries give me access denied, with C# code and Microsoft.SqlServer.Management.Smo.Agent namespace I just listed all jobs with this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo.Agent;
namespace SmoTest
{
class Program
{
static readonly string SqlServer = #"SQL01\SQL01";
static void Main(string[] args)
{
ServerConnection conn = new ServerConnection(SqlServer);
Server server = new Server(conn);
JobCollection jobs = server.JobServer.Jobs;
foreach (Job job in jobs)
{
Console.WriteLine(job.Name);
}
}
}
}
This should be a good starting point to find out how to find your SQL Agent jobs using T-SQL:
View (and disable) SQL Agent Jobs with TSQL
The script will list out all your jobs on your database, and when they will be run next and so forth.
Using the job_name, you should also be able to find out details about your jobs using the SQL Server Agent Stored Procedures in the msdb database on your server.
On SQL Server 2005 and above, you can use the system stored procedure msdb.dbo.sp_help_job to get information, including status, about SQL Server Agent Jobs. You can read more about sp_help_job at http://msdn.microsoft.com/en-us/library/ms186722(v=SQL.90).aspx.
Here is the sample code to do this from C#.
private Dictionary<int, string> ExecutionStatusDictionary = new Dictionary<int, string>()
{
{0, "Not idle or suspended"},
{1, "Executing"},
{2, "Waiting for thread"},
{3, "Between retries"},
{4, "Idle"},
{5, "Suspended"},
{7, "Performing completion actions"}
};
public string GetStatus()
{
SqlConnection msdbConnection = new SqlConnection("Data Source=SERVERNAME;Initial Catalog=msdb;Integrated Security=SSPI");
System.Text.StringBuilder resultBuilder = new System.Text.StringBuilder();
try
{
msdbConnection.Open();
SqlCommand jobStatusCommand = msdbConnection.CreateCommand();
jobStatusCommand.CommandType = CommandType.StoredProcedure;
jobStatusCommand.CommandText = "sp_help_job";
SqlParameter jobName = jobStatusCommand.Parameters.Add("#job_name", SqlDbType.VarChar);
jobName.Direction = ParameterDirection.Input;
jobName.Value = "LoadRegions";
SqlParameter jobAspect = jobStatusCommand.Parameters.Add("#job_aspect", SqlDbType.VarChar);
jobAspect.Direction = ParameterDirection.Input;
jobAspect.Value = "JOB";
SqlDataReader jobStatusReader = jobStatusCommand.ExecuteReader();
while (jobStatusReader.Read())
{
resultBuilder.Append(string.Format("{0} {1}",
jobStatusReader["name"].ToString(),
ExecutionStatusDictionary[(int)jobStatusReader["current_execution_status"]]
));
}
jobStatusReader.Close();
}
finally
{
msdbConnection.Close();
}
return resultBuilder.ToString();
}
You can get a list of all server jobs using this SELECT:
SELECT [name] FROM msdb.dbo.sysjobs
If you'd like to get a list of currently running jobs and their information, I would recommend writing a stored procedure in SQL which your application calls. There's a good demonstration here you could use...
http://feodorgeorgiev.com/blog/2010/03/how-to-query-currently-running-sql-server-agent-jobs/
Good luck!
For my use case, I specifically needed to know when the job was finished running, and whether or not it succeeded. Here is my code to do that:
using System;
using System.Data;
using System.Data.SqlClient;
namespace LaunchJobAndWaitTillDone
{
class Program
{
const string connectionString = "Data Source=YOURSERVERNAMEHERE;Initial Catalog=msdb;Integrated Security=SSPI";
const string jobName = "YOURJOBNAMEHERE";
static readonly TimeSpan waitFor = TimeSpan.FromSeconds(1.0);
enum JobExecutionResult
{
Succeeded,
FailedToStart,
FailedAfterStart,
Unknown
}
static void Main(string[] args)
{
var instance = new Program();
JobExecutionResult jobResult = instance.RunJob(jobName);
switch (jobResult)
{
case JobExecutionResult.Succeeded:
Console.WriteLine($"SQL Server Agent job, '{jobName}', ran successfully to completion.");
break;
case JobExecutionResult.FailedToStart:
Console.WriteLine($"SQL Server Agent job, '{jobName}', failed to start.");
break;
case JobExecutionResult.FailedAfterStart:
Console.WriteLine($"SQL Server Agent job, '{jobName}', started successfully, but encountered an error.");
break;
default:
Console.WriteLine($"Unknown result from attempting to run SQL Server Agent job, '{jobName}'.");
break;
}
Console.ReadLine();
return;
}
JobExecutionResult RunJob(string jobName)
{
int jobResult;
using (var jobConnection = new SqlConnection(connectionString))
{
SqlCommand jobCommand;
SqlParameter jobReturnValue;
SqlParameter jobParameter;
jobCommand = new SqlCommand("sp_start_job", jobConnection);
jobCommand.CommandType = CommandType.StoredProcedure;
jobReturnValue = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
jobReturnValue.Direction = ParameterDirection.ReturnValue;
jobCommand.Parameters.Add(jobReturnValue);
jobParameter = new SqlParameter("#job_name", SqlDbType.VarChar);
jobParameter.Direction = ParameterDirection.Input;
jobCommand.Parameters.Add(jobParameter);
jobParameter.Value = jobName;
jobConnection.Open();
try
{
jobCommand.ExecuteNonQuery();
jobResult = (Int32)jobCommand.Parameters["#RETURN_VALUE"].Value;
}
catch (SqlException)
{
jobResult = -1;
}
}
switch (jobResult)
{
case 0:
break;
default:
return JobExecutionResult.FailedToStart;
}
while (true)
{
using (var jobConnection2 = new SqlConnection(connectionString))
{
SqlCommand jobCommand2 = new SqlCommand("sp_help_jobactivity", jobConnection2);
jobCommand2.CommandType = CommandType.StoredProcedure;
SqlParameter jobReturnValue2 = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
jobReturnValue2.Direction = ParameterDirection.ReturnValue;
jobCommand2.Parameters.Add(jobReturnValue2);
SqlParameter jobParameter2 = new SqlParameter("#job_name", SqlDbType.VarChar);
jobParameter2.Direction = ParameterDirection.Input;
jobCommand2.Parameters.Add(jobParameter2);
jobParameter2.Value = jobName;
jobConnection2.Open();
SqlDataReader rdr = jobCommand2.ExecuteReader();
while (rdr.Read())
{
object msg = rdr["message"];
object run_status = rdr["run_status"];
if (!DBNull.Value.Equals(msg))
{
var message = msg as string;
var runStatus = run_status as Int32?;
if (message != null && message.StartsWith("The job succeeded")
&& runStatus.HasValue && runStatus.Value == 1)
{
return JobExecutionResult.Succeeded;
}
else if (message != null && message.StartsWith("The job failed"))
{
return JobExecutionResult.FailedAfterStart;
}
else if (runStatus.HasValue && runStatus.Value == 1)
{
return JobExecutionResult.Unknown;
}
}
}
}
System.Threading.Thread.Sleep(waitFor);
}
}
}
}
Note that you may need database/server owner permissions or something like that for this code to work.
Background:
I am trying to add data to a SQL DB with C#. I am currently doing so in my script in another class so im using the same code (the code works). However, my current class is using a bunch of recycled code and i am having issues narrowing down why i can not write to the DB. Below is the code i am using and it is broken down to the bare bones minimum code.
What I'm asking for:
anyone to point out some dumb mistake i made or ideas where to troubleshoot. Currently i am just staring at this code and cant see whats wrong.
Thanks in advance!
public void AddAttachmentToDB(XmlNode root, XmlNamespaceManager xmlns, string MessageID, string MailBoxAliasName)
{
//open DB
#region Open DB
if (DbConnection.State != System.Data.ConnectionState.Open)
{
try
{
this.DbConnection.ConnectionString = DbConnectionString;
this.DbConnection.Open();
MailboxListener._logging.LogWrite("[{0}] opened DB Connection in AddAttachmentToDB!",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
}
catch (Exception ex)
{
MailboxListener._logging.LogWrite("[{0}] Failed to open DB Connection! For Machine: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
MailboxListener._logging.LogWrite("[{0}] Error Returned: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
ex.Message.ToString());
}
}
else
{
MailboxListener._logging.LogWrite("[{0}] Failed to open DB Connection in AddAttachmentToDB!",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
}
#endregion
//once db is open try this
try
{
//create test variables
string strMailBoxAliasName = MailBoxAliasName;
string AttachmentFilename = string.Empty;
string strfiletype = string.Empty;
string AttachmentStream = string.Empty;
string strAttachmentID = string.Empty;
string strMessageID = string.Empty;
strMessageID = MessageID;
//fill test variables
AttachmentFilename = "yumyum";
AttachmentStream = "Cheetos";
strMessageID = "123";
strMailBoxAliasName = "user";
strfiletype = ".txt";
strAttachmentID = "12345";
//create sql insert string
String insString = #"INSERT INTO MailboxListenerAttachments Values (#attachmentfilename, #attachmentbody,
#messageID, #mailboxname, #filetype, #attachmentID, #DateAddedToDB)";
//create sql command string
SqlCommand myCommand = new SqlCommand(insString, this.DbConnection);
//add fill test variables to sql insert string
myCommand.Parameters.Add("#attachmentfilename", SqlDbType.VarChar, 100);
myCommand.Parameters["#attachmentfilename"].Value = AttachmentFilename;
myCommand.Parameters.Add("#attachmentbody", SqlDbType.VarChar, 8000);
myCommand.Parameters["#attachmentbody"].Value = AttachmentStream.Trim();
myCommand.Parameters.Add("#messageID", SqlDbType.VarChar, 500);
myCommand.Parameters["#messageID"].Value = strMessageID;
myCommand.Parameters.Add("#mailboxname", SqlDbType.VarChar, 100);
myCommand.Parameters["#mailboxname"].Value = strMailBoxAliasName;
myCommand.Parameters.Add("#filetype", SqlDbType.VarChar, 50);
myCommand.Parameters["#filetype"].Value = strfiletype;
myCommand.Parameters.Add("#attachmentID", SqlDbType.VarChar, 50);
myCommand.Parameters["#attachmentID"].Value = strAttachmentID;
myCommand.Parameters.Add("#DateAddedToDB", SqlDbType.DateTime);
myCommand.Parameters["#DateAddedToDB"].Value = DateTime.UtcNow.ToString();
//run sql command
myCommand.ExecuteNonQuery();
//log sql command events
MailboxListener._logging.LogWrite(
"[{0}] Added attachment {1} to database for messageID: {2}",
LoggingLevels.Informational,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
AttachmentFilename,
strMessageID
);
//if DB is open, close it
if (DbConnection.State == System.Data.ConnectionState.Open)
{
this.DbConnection.Close();
}
}
//catch errors
catch (Exception ex)
{
MailboxListener._logging.LogWrite("[{0}] Error Returned: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
ex.Message.ToString());
}
}
No idea why this doesn't work but this code screams for refactoring:
public void AddAttachmentToDB(
XmlNode root,
XmlNamespaceManager xmlns,
string MessageID,
string MailBoxAliasName
)
{
var strMailBoxAliasName = MailBoxAliasName;
var AttachmentFilename = "yumyum";
var AttachmentStream = "Cheetos";
var strMessageID = "123";
var strMailBoxAliasName = "user";
var strfiletype = ".txt";
var strAttachmentID = "12345";
// Use DateTime when working with dates
var dates123 = new DateTime(2011, 2, 3);
try
{
using (var conn = new SqlConnection(DbConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = #"INSERT INTO MailboxListenerAttachments Values (#attachmentfilename, #attachmentbody, #messageID, #mailboxname, #filetype, #attachmentID, #DateAddedToDB";
cmd.Parameters.AddWithValue("#attachmentfilename", AttachmentFilename);
cmd.Parameters.AddWithValue("#attachmentbody", AttachmentStream.Trim());
cmd.Parameters.AddWithValue("#messageID", strMessageID);
cmd.Parameters.AddWithValue("#mailboxname", strMailBoxAliasName);
cmd.Parameters.AddWithValue("#filetype", strfiletype);
cmd.Parameters.AddWithValue("#attachmentID", strAttachmentID);
cmd.Parameters.AddWithValue("#DateAddedToDB", dates123);
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// TODO: Log the exception and propagate it
throw ex;
}
}
Shouldn't Dates123 be of a DateTime type instead of a string?
I think you need to specify input/output directions for all of the paramters.
for example : myCommand.Parameters["#attachmentfilename"].Direction = ParameterDirection.Input
If you really have no idea you can try
Fix your insert statement so it
explicitly names columns maybe your
ordering is incorrect and insert
statement doesnt work
your setting parameters length to
maximum column length values, maybe you
need to set them to actual parameter
values length
I really think that Dates123 is
indeed the most important problem here, it
should be DateTime not string.
So you changed it but you still call DateTime.UtcNow.ToString() , leave it as DateTime type not string.
I am trying to get a winform app to refresh an embedded browser on a database change using Oracle 10g. The only problem is that I am not allowed to use Database Change Notification. I am curious if anyone has a way of using the built-in package of DBMS_Alert and have had some action happen to a winform app on a database change.
Thanks, Andrew
food for thought...
if you are using ODP, you could use Oracle Advanced Queuing/Streams
and here.
this way your form app can subscribe to a queue and be notified of a change.
This may, however, be massive overkill for your application if you just want to add a new PO # into a drop down!
I have used streams before and it works as expected, but it had a nice level of research and trial & error to get things to click.
I had to do it like this for it to work. It holds the window in lock until an event occurs i know, but at least it works with DBMS_Alert. I set this code inside a timer:
OracleConnection conn = new OracleConnection(ConnectionString);
conn.Open();
OracleCommand cmd = new OracleCommand("DECLARE\n" +
"MESSAGE VARCHAR2(1800) := null;\n" +
"STATUS INTEGER;\n" +
"BEGIN\n" +
"DBMS_ALERT.REGISTER('ALERT');\n" +
"DBMS_ALERT.WAITONE('ALERT', MESSAGE, STATUS);\n" +
"DBMS_ALERT.REMOVE('ALERT');\n" +
"END;", conn);
cmd.ExecuteNonQuery();
wbMain.Refresh();
conn.Dispose();
This gives me what I need. I don't know if there is a better way to do it, but this is the only solution I could come up with.
It is better to use without timer. The below code sample is with background thread
Here is the code snippet
privateThread DBMSAlertThread;
private void DBMSAlert(bool Register)
{
try
{
string sSql;
if (Register)
sSql = "call dbms_alert.register('XYZ')";
else
sSql = "call dbms_alert.remove('XYZ')";
dbmsAlert = new OracleCommand();
dbmsAlert.CommandText = sSql;
dbmsAlert.ExecuteNonQuery();
if (Register) //start the background thread
{
DBMSAlertThread = new Thread(AlertEvent);
DBMSAlertThread.IsBackground = true;
DBMSAlertThread.Start();
}
}
catch (Exception LclExp)
{
//Show error or capture in eventlog
}
}
private void AlertEvent(object sender)
{
while (true)
{
string Message = "";
int Status = -1;
bool bStatus;
OracleParameter param;
try
{
OracleCommand dbmsAlert = new OracleCommand();
dbmsAlertScan.SQL.Add("call dbms_alert.WaitOne('XYZ', :Message, :Status, 0)"); //Last parameter indicate wait time
param = new OracleParameter("Message", OracleDbType.Varchar2, ParameterDirection.Output);
dbmsAlert.Parameters.Add(param);
param = new OracleParameter("Status", OracleDbType.Varchar2, ParameterDirection.Output);
dbmsAlert.Parameters.Add(param);
OracleParameter.ExceuteNonQuery();
Message = dbmsAlert.Parameters["Message"].Value.ToString();
bStatus = int.TryParse(dbmsAlert.Parameters["Status"].Value.ToString(), out Status);
if (Status == 0) //0 = Alert Received, 1 = Timed out
{
//notify or do ur stuff
}
}
catch (Exception Exp)
{
//raise an error
}
}
}
I need to create an application for monitoring SQL Server 2000 Agent Job status and info when Job occur same as show on Windows application event log. Now I connect to the database already via a connection string, but I don't know how to get the status and info from Job.
I need to show status and info on Textbox.
What do you suggestion how to do.
Developer tools :
MS SQL Sever 2000 SP4
MS Visual Studio 2008 (C#)
I am a rookie programmer.
i can do this already...
i select form table "Sysjobserver" in database "msdb" for read status, date, time of job that i want.
use this code
public void GetJobsAndStatus()
{
string sqlJobQuery = "select j.job_id, j.name, j.enabled, jh.run_status," +
" js.last_outcome_message, jh.run_date, jh.step_name, jh.run_time" +
" from sysjobs j left join sysjobhistory jh on (j.job_id = jh.job_id)" +
" left join sysjobservers js on (j.job_id = js.job_id)" +
" where jh.run_date = (select Max(run_date) from sysjobhistory)" +
" and jh.run_time = (select Max(run_time) from sysjobhistory)";
// create SQL connection and set up SQL Command for query
using (SqlConnection _con = new SqlConnection("server=10.15.13.70;database=msdb;user id=sa;pwd="))
using (SqlCommand _cmd = new SqlCommand(sqlJobQuery, _con))
{
try
{
// open connection
_con.Open();
SqlConnection.ClearPool(_con);
// create SQL Data Reader and grab data
using (SqlDataReader rdr = _cmd.ExecuteReader())
{
// as long as we get information from the reader
while (rdr.Read())
{
Guid jobID = rdr.GetGuid(0); // read Job_id
string jobName = rdr.GetString(1); // read Job name
byte jobEnabled = rdr.GetByte(2); // read Job enabled flag
int jobStatus = rdr.GetInt32(3); // read last_run_outcome from sysjobserver
string jobMessage = rdr.GetString(4); // read Message from sysjobserver
int jobRunDate = rdr.GetInt32(5); // read run_date from sysjobhistory
string jobStepName = rdr.GetString(6); // read StepName from sysjobhistory
int jobRunTime = rdr.GetInt32(7); // read run_time from sysjobhistory
String[] lviData = new String[] // ตัวแปรอะเรย์ชื่อ lviData
{
jobID.ToString(),
jobName.ToString(),
jobStepName.ToString(),
jobMessage.ToString(),
jobStatus.ToString(),
jobRunDate.ToString(),
jobRunTime.ToString(),
//jobEnabled.ToString(),
};
newData = lviData;
DisplayList(); // for display data on datagridview
}
rdr.Close();
}
}
thank you for everybody help very much. :-D
SQL stored procedures of queries don't give you any system data unless you have db_owner rights on the msdb system database, at lease in SQL Server 2008. Therefore mentioned methods normally don't work for applications where you want to show or manage jobs. However SMO namespace provides you with managed code solution for many SQL Server management features, including the SQL Server Agent functions that only require SQLServerAgent* permissions that you normally could get sorted for your application user. A good intro of using SMO classes to work with jobs is given here:
http://www.codeproject.com/Tips/367470/Manage-SQL-Server-Agent-Jobs-using-Csharp
I work on a similar task now and whilst SQL queries give me access denied, with C# code and Microsoft.SqlServer.Management.Smo.Agent namespace I just listed all jobs with this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo.Agent;
namespace SmoTest
{
class Program
{
static readonly string SqlServer = #"SQL01\SQL01";
static void Main(string[] args)
{
ServerConnection conn = new ServerConnection(SqlServer);
Server server = new Server(conn);
JobCollection jobs = server.JobServer.Jobs;
foreach (Job job in jobs)
{
Console.WriteLine(job.Name);
}
}
}
}
This should be a good starting point to find out how to find your SQL Agent jobs using T-SQL:
View (and disable) SQL Agent Jobs with TSQL
The script will list out all your jobs on your database, and when they will be run next and so forth.
Using the job_name, you should also be able to find out details about your jobs using the SQL Server Agent Stored Procedures in the msdb database on your server.
On SQL Server 2005 and above, you can use the system stored procedure msdb.dbo.sp_help_job to get information, including status, about SQL Server Agent Jobs. You can read more about sp_help_job at http://msdn.microsoft.com/en-us/library/ms186722(v=SQL.90).aspx.
Here is the sample code to do this from C#.
private Dictionary<int, string> ExecutionStatusDictionary = new Dictionary<int, string>()
{
{0, "Not idle or suspended"},
{1, "Executing"},
{2, "Waiting for thread"},
{3, "Between retries"},
{4, "Idle"},
{5, "Suspended"},
{7, "Performing completion actions"}
};
public string GetStatus()
{
SqlConnection msdbConnection = new SqlConnection("Data Source=SERVERNAME;Initial Catalog=msdb;Integrated Security=SSPI");
System.Text.StringBuilder resultBuilder = new System.Text.StringBuilder();
try
{
msdbConnection.Open();
SqlCommand jobStatusCommand = msdbConnection.CreateCommand();
jobStatusCommand.CommandType = CommandType.StoredProcedure;
jobStatusCommand.CommandText = "sp_help_job";
SqlParameter jobName = jobStatusCommand.Parameters.Add("#job_name", SqlDbType.VarChar);
jobName.Direction = ParameterDirection.Input;
jobName.Value = "LoadRegions";
SqlParameter jobAspect = jobStatusCommand.Parameters.Add("#job_aspect", SqlDbType.VarChar);
jobAspect.Direction = ParameterDirection.Input;
jobAspect.Value = "JOB";
SqlDataReader jobStatusReader = jobStatusCommand.ExecuteReader();
while (jobStatusReader.Read())
{
resultBuilder.Append(string.Format("{0} {1}",
jobStatusReader["name"].ToString(),
ExecutionStatusDictionary[(int)jobStatusReader["current_execution_status"]]
));
}
jobStatusReader.Close();
}
finally
{
msdbConnection.Close();
}
return resultBuilder.ToString();
}
You can get a list of all server jobs using this SELECT:
SELECT [name] FROM msdb.dbo.sysjobs
If you'd like to get a list of currently running jobs and their information, I would recommend writing a stored procedure in SQL which your application calls. There's a good demonstration here you could use...
http://feodorgeorgiev.com/blog/2010/03/how-to-query-currently-running-sql-server-agent-jobs/
Good luck!
For my use case, I specifically needed to know when the job was finished running, and whether or not it succeeded. Here is my code to do that:
using System;
using System.Data;
using System.Data.SqlClient;
namespace LaunchJobAndWaitTillDone
{
class Program
{
const string connectionString = "Data Source=YOURSERVERNAMEHERE;Initial Catalog=msdb;Integrated Security=SSPI";
const string jobName = "YOURJOBNAMEHERE";
static readonly TimeSpan waitFor = TimeSpan.FromSeconds(1.0);
enum JobExecutionResult
{
Succeeded,
FailedToStart,
FailedAfterStart,
Unknown
}
static void Main(string[] args)
{
var instance = new Program();
JobExecutionResult jobResult = instance.RunJob(jobName);
switch (jobResult)
{
case JobExecutionResult.Succeeded:
Console.WriteLine($"SQL Server Agent job, '{jobName}', ran successfully to completion.");
break;
case JobExecutionResult.FailedToStart:
Console.WriteLine($"SQL Server Agent job, '{jobName}', failed to start.");
break;
case JobExecutionResult.FailedAfterStart:
Console.WriteLine($"SQL Server Agent job, '{jobName}', started successfully, but encountered an error.");
break;
default:
Console.WriteLine($"Unknown result from attempting to run SQL Server Agent job, '{jobName}'.");
break;
}
Console.ReadLine();
return;
}
JobExecutionResult RunJob(string jobName)
{
int jobResult;
using (var jobConnection = new SqlConnection(connectionString))
{
SqlCommand jobCommand;
SqlParameter jobReturnValue;
SqlParameter jobParameter;
jobCommand = new SqlCommand("sp_start_job", jobConnection);
jobCommand.CommandType = CommandType.StoredProcedure;
jobReturnValue = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
jobReturnValue.Direction = ParameterDirection.ReturnValue;
jobCommand.Parameters.Add(jobReturnValue);
jobParameter = new SqlParameter("#job_name", SqlDbType.VarChar);
jobParameter.Direction = ParameterDirection.Input;
jobCommand.Parameters.Add(jobParameter);
jobParameter.Value = jobName;
jobConnection.Open();
try
{
jobCommand.ExecuteNonQuery();
jobResult = (Int32)jobCommand.Parameters["#RETURN_VALUE"].Value;
}
catch (SqlException)
{
jobResult = -1;
}
}
switch (jobResult)
{
case 0:
break;
default:
return JobExecutionResult.FailedToStart;
}
while (true)
{
using (var jobConnection2 = new SqlConnection(connectionString))
{
SqlCommand jobCommand2 = new SqlCommand("sp_help_jobactivity", jobConnection2);
jobCommand2.CommandType = CommandType.StoredProcedure;
SqlParameter jobReturnValue2 = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
jobReturnValue2.Direction = ParameterDirection.ReturnValue;
jobCommand2.Parameters.Add(jobReturnValue2);
SqlParameter jobParameter2 = new SqlParameter("#job_name", SqlDbType.VarChar);
jobParameter2.Direction = ParameterDirection.Input;
jobCommand2.Parameters.Add(jobParameter2);
jobParameter2.Value = jobName;
jobConnection2.Open();
SqlDataReader rdr = jobCommand2.ExecuteReader();
while (rdr.Read())
{
object msg = rdr["message"];
object run_status = rdr["run_status"];
if (!DBNull.Value.Equals(msg))
{
var message = msg as string;
var runStatus = run_status as Int32?;
if (message != null && message.StartsWith("The job succeeded")
&& runStatus.HasValue && runStatus.Value == 1)
{
return JobExecutionResult.Succeeded;
}
else if (message != null && message.StartsWith("The job failed"))
{
return JobExecutionResult.FailedAfterStart;
}
else if (runStatus.HasValue && runStatus.Value == 1)
{
return JobExecutionResult.Unknown;
}
}
}
}
System.Threading.Thread.Sleep(waitFor);
}
}
}
}
Note that you may need database/server owner permissions or something like that for this code to work.