Click here to Skip to main content
15,886,518 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I need to generate and send a report to customers as per they configured in a portal. We have almost 30 clients, and each client has 20-25 reports. Clients have access to the portal and they can configure their report timing by any day/monthly/yearly.

For example, if client A scheduled 5 reports:

report a ---> daily @ 10PM
report b ---> monthly once on date 02 @ 10AM
report c ---> yearly once on date 30/june @ 5PM
report d ---> daily @ 12PM
report e ---> monthly once on date 02 @ 10AM


in the same way, all clients have the privilege to configure their reports respectively in the UI. We are capturing all the details in databases.

we have a code written with a pattern that it will convert the datatable to pdf and send the pdf as an attachment to the configured email written in C#.

The question here is, how will I get to know at what time and to which client the report needs to be generated. I need the advice/idea to follow the above question to send the report to the respective client.

If one client we can write a batch console and trigger that console by schedule jobs, but here we have more than 30 clients. So please suggest me some ideas/technology that I can follow and complete this work without any problem

What I have tried:

please suggest me some ideas/technology that I can follow and complete this work without any problem
Posted
Updated 15-Jun-20 3:29am
Comments
Maciej Los 15-Jun-20 9:17am    

I would look at a central scheduling service - possibly C# based, using Topshelf for the service framework, Quartz for the cron based scheduled activities kicking a 'message' out via RabbitMQ, where 'messsage' is the Client + Job + Parameters

Then a number of machines subscribe to the RabbitMQ messages - perhaps by client(s) or some other technique that lets you distribute the work - and runs the relevant report job using the details in the message
 
Share this answer
 
In addition to Garth's answer, you can also use the Windows Task Scheduler to create and execute tasks on remote computers, see: Schtasks.exe - Win32 apps | Microsoft Docs[^]
Personally I prefer to call the Windows Task Scheduler with Process.Start() as I find the existing libraries too complex and also think problems can arise when things change after a Windows update.

Here is a example for local usage:
private void CreateSchedulerTask(string scheduleTime)
{
	var command = Path.Combine(Environment.SystemDirectory, @"SchTasks");
	var args = "/Query";
	var result = Utilities.ProcessRun(command, args, true);

	if (result.Contains("MyTaskName"))
	{
		Debug.Print("MyTaskName already running.");
		return;
	}

	command = Path.Combine(Environment.SystemDirectory, @"SchTasks");
	args = "/Create /SC WEEKLY /D MON /TN \"MyTaskName\" /TR \"" + Application.ExecutablePath + "\" /ST " + scheduleTime;
	Debug.Print(command + "  " + args);
	result = Utilities.ProcessRun(command, args, false);
}

public static string ProcessRun(string fileName, string args, bool redirectStandardOutput, bool waitForExit = true, bool hideWindow = false)
{
	string result = string.Empty;
	const int ErrorCancelled = 1223;

	try
	{
		using (Process process = new Process())
		{
			process.StartInfo = new ProcessStartInfo();
			process.StartInfo.FileName = fileName;

			if (hideWindow)
			{
				process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
			}

			if (!string.IsNullOrEmpty(args))
			{
				process.StartInfo.Arguments = args;
			}

			process.StartInfo.CreateNoWindow = true;

			if (redirectStandardOutput)
			{
				process.StartInfo.RedirectStandardOutput = true;
				process.StartInfo.UseShellExecute = false;
				process.Start();

				using (StreamReader reader = process.StandardOutput)
				{
					string resultOut = reader.ReadToEnd();
					Debug.Print(resultOut);
				}
			}
			else
			{
				process.StartInfo.Verb = "runas";
				process.StartInfo.UseShellExecute = true;
				process.Start();
			}

			if (waitForExit)
			{
				// Timeout 2 minutes
				process.WaitForExit(120000);
			}
		}
	}
	catch (Win32Exception ex)
	{
		if (ex.NativeErrorCode == ErrorCancelled)
		{
			result = "ProcessRun() cancelled";
		}
		else
		{
			result = @"ProcessRun() error: " + ex.Message;
		}
	}
	catch (Exception ex)
	{
		result = @"ProcessRun() error: " + ex.Message;
	}

	return result;
}
 
Share this answer
 
v2
For MS SQL Server database:

You can create a stored procedure as is described here: c# - Create SQL Server Agent jobs programatically - Stack Overflow[^]

Whenever a client will create schedule, you can use such of procedure to create sql server job programmatically.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900