Converting Console app to Windows Service - c#

Am trying to convert my console application, which generates pdf reports, into a windows service. My code is as follows. Am I on the right direction? I installed this service and start/stop works fine but no report is generated! The console app alone works fine to generate Output.pdf. My aim is to Generate ouput when the service starts.
class Program : ServiceBase
{
public Program()
{
this.ServiceName = "My PdfGeneration";
}
static void Main(string[] args)
{
ServiceBase.Run(new Program());
}
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("My PdfGeneration Started");
//base.OnStart(args);
//Customise parameters for render method
Warning[] warnings;
string[] streamIds;
string mimeType = string.Empty; //"application/pdf";
string encoding = string.Empty;
string filenameExtension = string.Empty;
string deviceInfo = "<DeviceInfo>" + "<OutputFormat>PDF</OutputFormat>" + "<PageWidth>15in</PageWidth>" + "<PageHeight>11in</PageHeight>" + "<MarginTop>0.5in</MarginTop>" + "<MarginLeft>0.5in</MarginLeft>" + "<MarginRight>0.5in</MarginRight>" + "<MarginBottom>0.5in</MarginBottom>" + "</DeviceInfo>";
//Create a SqlConnection to the AdventureWorks2008R2 database.
SqlConnection connection = new SqlConnection("data source=localhost;initial catalog=pod;integrated security=True");
//Create a SqlDataAdapter for the Sales.Customer table.
SqlDataAdapter adapter = new SqlDataAdapter();
// A table mapping names the DataTable.
adapter.TableMappings.Add("View", "Route_Manifest");
// Open the connection.
connection.Open();
Console.WriteLine("\nThe SqlConnection is open.");
// Create a SqlCommand to retrieve Suppliers data.
SqlCommand command = new SqlCommand("SELECT TOP 10 [RouteID],[FullTruckID],[DriverID],[DriverName],[StopID],[CustomerID],[CustomerName],[InvoiceID],[last_modified],[Amount] FROM [pod].[dbo].[Route_Manifest]", connection);
command.CommandType = CommandType.Text;
// Set the SqlDataAdapter's SelectCommand.
adapter.SelectCommand = command;
command.ExecuteNonQuery();
// Fill the DataSet.
DataSet dataset = new DataSet("Route_Manifest");
adapter.Fill(dataset);
//Set up reportviewver and specify path
ReportViewer viewer = new ReportViewer();
viewer.ProcessingMode = ProcessingMode.Local;
viewer.LocalReport.ReportPath = #"C:\Documents and Settings\xxxxx\My Documents\Visual Studio 2008\Projects\PdfReportGeneration\PdfReportGeneration\Report.rdlc";
//specify the dataset syntax = (datasetofreport.rdlc,querydataset);
viewer.LocalReport.DataSources.Add(new ReportDataSource("podDataSet_Route_Manifest", dataset.Tables[0]));
//Now render it to pdf
try
{
byte[] bytes = viewer.LocalReport.Render("PDF", deviceInfo, out mimeType, out encoding, out filenameExtension, out streamIds, out warnings);
//output to bin directory
using (System.IO.FileStream fs = new System.IO.FileStream("output.pdf", System.IO.FileMode.Create))
{
//file saved to bin directory
fs.Write(bytes, 0, bytes.Length);
}
Console.WriteLine("\n YEP!! The report has been generated:-)");
/* //Save report to D:\ -- later
FileStream fsi = new FileStream(#"D:\output.pdf", System.IO.FileMode.Create);
*/
}
catch (Exception e)
{
Console.WriteLine("\n CHEY!!!this Exception encountered:", e);
}
// Close the connection.
connection.Close();
Console.WriteLine("\nThe SqlConnection is closed.");
Console.ReadLine();
}
protected override void OnStop()
{
EventLog.WriteEntry("My PdfGeneration Stopped");
base.OnStop();
}
}

I would advise that you move the code in your OnStart event to a separate thread, since
your service will need to start in a timely matter, else it can potentially time out
on start up.
E.g
using System.ServiceProcess;
using System.Threading;
namespace myService
{
class Service : ServiceBase
{
static void Main()
{
ServiceBase.Run(new Service());
}
public Service()
{
Thread thread = new Thread(Actions);
thread.Start();
}
public void Actions()
{
// Do Work
}
}
}
You might also want to check if the executing user (user context in which the service runs)
has rights to the folder you're writing to etc.
You will also need to write your errors to the event log instead of writing them to the
console window like seen in your snippet (your code is swallowing exceptions at the moment
thats why you cant pin point whats going wrong)
Read more over here:
C# Basics: Creating a Windows Service

Yes and no, what you should do is to define what OperationContract you are in the process of exposing by defining an interface.
For instance see this on channel 9:
http://channel9.msdn.com/Shows/Endpoint/Endpoint-Screencasts-Creating-Your-First-WCF-Service
you should define this service is a separate library assembly (because tomorrow you'll want to host this service somewhere else and very likely while developing, in a console application).
consuming the service you need to consider if it should be from an asp.net web page, a windows forms program or a console utility, really depending on your consumer scenario you'd want to externalize the actual pdf functionality in a separate class (in same library assembly) so that the day you want to just be able to do that in one of you other programs, it will not have to communicate with a wcf service somewhere on the network, though such a thing is nifty in itself it affects performance to integrate across process to a limited degree.

Related

create Database with .net installshield 2015

I'm trying to create an installer file that installs a database using install shield 2015.
I'm following this link
Walkthrough: Using a Custom Action to Create a Database at Installation
Since this link refers to an older install shield I didn't managed to make it work. I have created an install file in my main windows form application, which you can see in the below code.
public partial class DeployInstaller : System.Configuration.Install.Installer
{
System.Data.SqlClient.SqlConnection masterConnection = new System.Data.SqlClient.SqlConnection();
public DeployInstaller()
{
InitializeComponent();
}
private string GetSql(string Name)
{
try
{
// Gets the current assembly.
Assembly Asm = Assembly.GetExecutingAssembly();
// Resources are named using a fully qualified name.
Stream strm = Asm.GetManifestResourceStream(Asm.GetName().Name + "." + Name);
// Reads the contents of the embedded file.
StreamReader reader = new StreamReader(strm);
return reader.ReadToEnd();
}
catch (Exception ex)
{
//Interaction.MsgBox("In GetSQL: " + ex.Message);
throw ex;
}
}
private void ExecuteSql(string Sql)
{
masterConnection.ConnectionString = "data source=.//SQLEXPRESS;initial catalog=master;integrated security=True; MultipleActiveResultSets=True; Application Name=EntityFramework";
System.Data.SqlClient.SqlCommand Command = new System.Data.SqlClient.SqlCommand(Sql, masterConnection);
// Initialize the connection, open it, and set it to the "master" database
Command.Connection.Open();
try
{
Command.ExecuteNonQuery();
}
finally
{
// Closing the connection should be done in a Finally block
Command.Connection.Close();
}
}
protected void AddDBTable()
{
try
{
// Creates the database.
//ExecuteSql("master", "CREATE DATABASE " + strDBName);
// Creates the tables.
ExecuteSql( GetSql("sql.txt"));
}
catch (Exception ex)
{
// Reports any errors and abort.
//Interaction.MsgBox("In exception handler: " + ex.Message);
throw ex;
}
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
AddDBTable();
}
}
Supposedly this piece of code provides the user with the ability of doing both the installation of the system and the corresponding database. For some reason only the system is being installed. When attempting to install the database, something is preventing from successfully completing. Unfortunately, I cannot pinpoint the reason why because it doesn't give out an error with the reason. It could be that its never being started or that I did something wrong.
Any guide would be appreciated.

how to keep sql dependency doing the its purpose

I have a console application.
I wanna keep watching the changes on a specific column in my database table.
I read through internet and I have found that sql dependency is good for my purpose. I started learning about it and I did the following:
create a class.
In the constructor, I called the static function start and I called a function that has all the sql dependency settings.
My problem
When I run the application using the start click on visual studio 2013, the apps works and then stops. However, what I need is that the apps starts working and keep watching for changes in my database's table.
Could you help me please?
Code:
This is a very very simple c# code.
public class MyListener
{
public MyListener()
{
SqlDependency.Start(getConnectionString());
this.listen();
}
private string getConnectionString()
{
return ConfigurationManager.ConnectionStrings["popup"].ConnectionString.ToString();
}
private void listen()
{
string query = "SELECT CallerID FROM TransferToSIP WHERE hasBeenRead = 0";
SqlConnection con = new SqlConnection(getConnectionString());
SqlCommand cmd = new SqlCommand(query, con);
con.Open();
using (cmd)
{
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += new
OnChangeEventHandler(OnDependencyChange);
using (SqlDataReader reader = cmd.ExecuteReader())
{
}
}
}
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
Console.WriteLine("Roma");
}
void Termination()
{
SqlDependency.Stop(getConnectionString());
Console.Read();
}
The problem is in absence of the resubscruption. You should call the listen method inside of OnDependencyChange. I know that it is weird, but it is the SqlDependency class.
Be careful using the SqlDependency class to monitor changes in the database tables - it has the problems with the memory leaks. However, you can use your own realization with DDL triggers and SQL Service Broker API or use one of an open source projects, e.g. SqlDependencyEx:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
Hope this helps.

C#: annoying mistake during making back up of sql database

I am trying to make my application which have aim to make backup of database on disk and also send it through ftp or mail.
So I made a research and finally I wrote project of Windows service and another project in console which is making a backup of database. Both are working well and both are written in the same Visual Studio but when I am trying to put code of making backups in Windows service it doesn't work. I can't understand why. I tried put code instead of example (which is creating a file and writing one line there and this part is working well) and I even tried to make another method to do it and then call this method.
Windows service is completely the same as here and in the SpadesAdminService class instead of
System.Diagnostics.EventLog.WriteEntry("SpadesAdminSvc",
ServiceName + "::Execute()");
I made this code (is working well - making an empty file on my disk every 5 seconds, should be written "text to file" but files are appearing !):
using (FileStream fs = File.OpenWrite("C:\\place\\" + DateTime.Now.ToString("ddMMyyyy_HHmmss") + ".txt"))
{
Byte[] napis = new UTF8Encoding(true).GetBytes("text to files"));
fs.Write(napis, 0, napis.Length);
}
My class of making back up (alone is also working well):
namespace makeBackUpConsole
{
class Program
{
static void Main(string[] args)
{
string dbname = "exampleToniDatabase";
SqlConnection sqlcon = new SqlConnection();
SqlCommand sqlcmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
sqlcon.ConnectionString = #"Server=GRAFIKA-2\SQLEXPRESS;Integrated Security=True;" + "Database=exampleToniDatabase";
string destdir = "C:\\place\\";
if (!System.IO.Directory.Exists(destdir))
{
System.IO.Directory.CreateDirectory("C:\\place\\");
}
try
{
sqlcon.Open();
sqlcmd = new SqlCommand("backup database " + dbname + " to disk='" + destdir + "\\" + DateTime.Now.ToString("ddMMyyyy_HHmmss") + ".Bak'", sqlcon);
sqlcmd.ExecuteNonQuery();
sqlcon.Close();
MessageBox.Show("Backup database successfully");
}
catch (Exception ex)
{
MessageBox.Show("Error During backup database!");
}
}
}
}
I am copying this class instead of my code to making txt files and Windows Service is not working. Here is a code:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Windows.Forms;
namespace toni.exampleService.Services
{
public class exampleAdminService : exampleServiceBase
{
public exampleAdminService()
{
this.ServiceName = "exampleAdminSvc";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
}
protected override void OnStop()
{
base.OnStop();
}
protected override int Execute()
{
//using (FileStream fs = File.OpenWrite("C:\\development\\toni\\dd\\" + DateTime.Now.ToString("ddMMyyyy_HHmmss") + ".txt"))
//{
// Byte[] napis = new UTF8Encoding(true).GetBytes("DzieƄ i godzina: " + DateTime.Now.ToString("ddMMyyyy_HHmmss"));
// fs.Write(napis, 0, napis.Length);
//}
string dbname = "exampleToniDatabase";
SqlConnection sqlcon = new SqlConnection();
SqlCommand sqlcmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
sqlcon.ConnectionString = #"Server=GRAFIKA-2\SQLEXPRESS;Integrated Security=True;" + "Database=exampleToniDatabase";
string destdir = "C:\\place\\";
if (!System.IO.Directory.Exists(destdir))
{
System.IO.Directory.CreateDirectory("C:\\place\\");
}
try
{
sqlcon.Open();
sqlcmd = new SqlCommand("backup database " + dbname + " to disk='" + destdir + "\\" + DateTime.Now.ToString("ddMMyyyy_HHmmss") + ".Bak'", sqlcon);
sqlcmd.ExecuteNonQuery();
sqlcon.Close();
MessageBox.Show("Backup database successfully");
}
catch (Exception ex)
{
MessageBox.Show("Error During backup database!");
}
return 0;
}
}
}
Of course all libraries as well linked.
Looking for any advice, please help me.
Thank you in advance and have a nice day.
edit:
Hey, problem solved.
I created a database account (not Windows account) in sql management studio and I putted this account User Id and Password directly into my code in C# in Windows Service.
Anyway maybe somebody will use my code :)
Thanks for reply.
Have you checked that a Windows Service has permissions to write a file in the location you are specifying. Services don't necessarily run as a user, so don't assume that where you can write a file your service can too.
Have you tried writing to a folder underneath c:\ProgramData?
If you don't know precisely what the problem is then you need to find out. Try adding System.Diagnostics.Debugger.Launch(); at service startup and then track the changes inside the debugger.
The Windows Service you have programmed is using "Integrated Security" for your SQL Server.
If you don't want to enter login credentials in your code, you should either set the executing user to your local account or grant the required user (e.g. LocalSystem) access to your database in your SQL Management Studio.
Usually a Windows Service is running as LocalSystem, LocalService or NetworkService. Just change the setting for your Windows Service in services.msc

continuous stream on IIS server - will it crash and how can i best execute this code?

I am currently developing a twitter streaming web app as part of a College proj. I have written code that uses curl to stream from twitter and writes the data to a sql server 2008 express database.
ProcessStartInfo curl = new ProcessStartInfo();
Process process = new Process();
protected void Page_Load(object sender, EventArgs e)
{
curl.FileName = #"c:\program files\Curl\curl.exe";
curl.Arguments = "http://stream.twitter.com/1/statuses/sample.json -u username:password";
curl.UseShellExecute = false;
curl.RedirectStandardOutput = true;
process = Process.Start(curl);
Twitter_Stream(sender, e);
}
protected void Twitter_Stream(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection();
// Start curl process
using (process)
{
using (StreamReader reader = process.StandardOutput)
{
try
{
// create connection and open connection
conn = new SqlConnection(ConfigurationManager.AppSettings["strConnectionString"].ToString());
conn.Open();
// Post the output from curl to the queue.
// One line = one tweet in json format.
while (!reader.EndOfStream)
{
// create a SqlCommand object for this connection
SqlCommand command = conn.CreateCommand();
command.CommandText = "save_stream";
string result = reader.ReadLine();
Message message = new Message(result);
JObject obj = JObject.Parse(message.Body.ToString());
/* I parse the obj here and exec query to save data
command.CommandType = CommandType.StoredProcedure;
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{ /*DO some error logging here.*/}
finally
{
// close the connection
conn.Close();
Thread.Sleep(1000);
Twitter_Stream(sender, e);
}
}
}
}`
My question is, As i have put a while loop that will or should never end in my code, will this cause an issue on the server load. Will a continuous loop crash the server? Also what should I use instead?
Any help at all would be much appreciated.
No, this will not crash the server because IIS is already watching for this case. If a page's execution time is greater than the currrent threshold, IIS will kill the thread.
Instead of making this a webpage, you should make this a console application. You can use infinite loops as much as you want in those.

SQL Compact allow only one WCF Client

I write a little Chat Application. To save some infos like Username and Password I store the Data in an SQL-Compact 3.5 SP1 Database.
Everything working fine, but If another (the same .exe on the same machine) Client want to access the Service. It came an EndpointNotFound exception, from the ServiceReference.Class.Open() at the Second Client.
So i remove the CE Data Access Code and I get no Error (with an if (false))
Where is the Problem?
I googled for this, but no one seems the same error I get :(
SOLUTION
I used the wrapper in
http://csharponphone.blogspot.com/2007/01/keeping-sqlceconnection-open-and-thread.html
for threat safty, and now it works :)
Client Code:
public test()
{
var newCompositeType = new Client.ServiceReference1.CompositeType();
newCompositeType.StringValue = "Hallo" + DateTime.Now.ToLongTimeString();
newCompositeType.Save = (Console.ReadKey().Key == ConsoleKey.J);
ServiceReference1.Service1Client sc = new Client.ServiceReference1.Service1Client();
sc.Open();
Console.WriteLine("Save " + newCompositeType.StringValue);
sc.GetDataUsingDataContract(newCompositeType);
sc.Close();
}
Server Code
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite.Save)
{
SqlCeConnection con = new SqlCeConnection(Properties.Settings.Default.Con);
con.Open();
var com = con.CreateCommand();
com.CommandText = "SELECT * FROM TEST";
SqlCeResultSet result = com.ExecuteResultSet(ResultSetOptions.Scrollable | ResultSetOptions.Updatable);
var rec = result.CreateRecord();
rec["TextField"] = composite.StringValue;
result.Insert(rec);
result.Close();
result.Dispose();
com.Dispose();
con.Close();
con.Dispose();
}
return composite;
}
You're not closing the connection before disposing the con object.
Try:
con.Close();
con.Dispose();
Could be an exception occuring during the service initialisation when the second client connects. Debug the service at the same time as running the second exe,
Set exception behaviour in VS to break when Common Language Runtime Exceptions are thrown as well as when they're unhandled and you'll see the error.
As tomlog's answer states - it could be because you're not closing the connection properly.
I used the wrapper in http://csharponphone.blogspot.com/2007/01/keeping-sqlceconnection-open-and-thread.html for threat safty, and now it works :)

Categories

Resources