SQL Server · Execute
Progress messages from a procedure
The messages a procedure sends while it runs, in two scenarios: PRINT and RAISERROR of severity 10 or less (information, not errors; SQL Server reports their severity as 0) come back in Messages, in order, for the application to show or log as it chooses (ARX never writes them to a log); CollectMessages = false leaves them out.
Set up for this page
The scenarios build on the sample application: SampleContext.cs (the dbContext every sample is given); SampleOutput.cs (Step and Show, which print); SampleContext.Application.cs (dbContext.Service, the application's ARX service); SampleCatalog.cs (the tables' ids, keys, lookups and display names).
1 The messages, in order
An import of 1,000 rows: a progress message every 250 rows, then one because it's large.
Already in scope: service (ArxMsSqlDbService)
var result = await service.ExecuteAsync(Import(1_000));
foreach (var message in result.Messages)
{
Console.WriteLine($"{message.Severity,-7} {message.Text}");
}Defined once in this sample.
private static ArxProcedureExpression Import(int rows)
{
var procedure = new ArxProcedureExpression("sp_import_progress");
procedure.AddParameter("p_rows", rows);
return procedure;
}Check it in the database
Run it in any SQL tool connected to the database, after the code has run.
SELECT name, type_desc
FROM sys.objects
WHERE name = 'sp_import_progress';Expect: sp_import_progress, SQL_STORED_PROCEDURE (the messages themselves are only seen by the session that ran the call).
2 Not collected
The same call without collecting them.
Already in scope: service (ArxMsSqlDbService)
var result = await service.ExecuteAsync(Import(1_000), new ArxExecuteOptions { CollectMessages = false });
Console.WriteLine($"{result.Messages.Count} messages");Defined once in this sample.
private static ArxProcedureExpression Import(int rows)
{
var procedure = new ArxProcedureExpression("sp_import_progress");
procedure.AddParameter("p_rows", rows);
return procedure;
}Check it in the database
Run it in any SQL tool connected to the database, after the code has run.
SELECT COUNT(*)
FROM sys.procedures
WHERE name = 'sp_import_progress';Expect: 1.
Run the complete sample
The code above comes from one program, built in a fresh project and run against the database. To run it yourself, here is every file and step.
The program, its files and how to run it
Run it locally
- .NET SDK: .NET SDK 10.0.100 or later 10.0.x (target
net10.0). - Create the project:
Terminal dotnet new console -n ArxSample -f net10.0 cd ArxSample - Install the packages:
Terminal dotnet add package ARX.SDK.SQL --version 1.0.0-rc.1 - Database: a SQL Server 2022 (tested with 16.0.4225.2) database with the sample schema.
- Configuration: set
ARX_SAMPLES_SQLSERVERto its connection string. Nothing is hard-coded. - Source code: add the files of the sample application this sample uses (
SampleContext.cs,SampleOutput.cs,SampleContext.Application.cs,SampleCatalog.cs), then replaceProgram.csand add the other file below, with the file names shown. - Run it:
Terminal dotnet run - Expected output: below.
The files
Runs the sample. Generated for this page; it reads the connection string from the environment.
using ArxSamples.MSSQL;
using ArxSamples.MSSQL.Operations.Execute.RealCases;
// The connection string comes from the environment, never from the code (see "Configure the connection").
var connectionString = Environment.GetEnvironmentVariable("ARX_SAMPLES_SQLSERVER")
?? throw new InvalidOperationException("Set the ARX_SAMPLES_SQLSERVER environment variable to your SQL Server connection string.");
await new RealCase6_ProgressMessages().RunAsync(new SampleContext(connectionString));
The sample, as it is in the repository.
using ARX.SDK.Query;
using ARX.SDK.Services;
using static ArxSamples.MSSQL.SampleOutput;
namespace ArxSamples.MSSQL.Operations.Execute.RealCases;
/// <summary>
/// The messages a procedure sends while it runs, in two scenarios: <c>PRINT</c> and <c>RAISERROR</c> of severity 10 or
/// less (information, not errors; SQL Server reports their severity as 0) come
/// back in <see cref="ArxExecuteResult.Messages"/>, in order, for the application to show or log as it chooses (ARX never
/// writes them to a log); <c>CollectMessages = false</c> leaves them out.
/// </summary>
public sealed class RealCase6_ProgressMessages : ISample
{
public string Name => "execute-real-6-progress-messages";
public string Title => "Progress messages from a procedure";
public async Task RunAsync(SampleContext dbContext)
{
await Scenario1_TheMessagesInOrderAsync(dbContext);
await Scenario2_NotCollectedAsync(dbContext);
}
private static ArxProcedureExpression Import(int rows)
{
var procedure = new ArxProcedureExpression("sp_import_progress");
procedure.AddParameter("p_rows", rows);
return procedure;
}
/// <summary>1. An import of 1,000 rows: a progress message every 250 rows, then one because it's large.</summary>
private static async Task Scenario1_TheMessagesInOrderAsync(SampleContext dbContext)
{
Step("1. The messages, in order");
var result = await dbContext.Service.ExecuteAsync(Import(1_000));
foreach (var message in result.Messages)
{
Show($"{message.Severity,-7} {message.Text}");
}
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT name, type_desc
* FROM sys.objects
* WHERE name = 'sp_import_progress';
* -- Expect: sp_import_progress, SQL_STORED_PROCEDURE (the messages themselves are only seen by the session that ran the call).
* ===========================================================
*/
}
/// <summary>2. The same call without collecting them.</summary>
private static async Task Scenario2_NotCollectedAsync(SampleContext dbContext)
{
Step("2. Not collected");
var result = await dbContext.Service.ExecuteAsync(Import(1_000), new ArxExecuteOptions { CollectMessages = false });
Show($"{result.Messages.Count} messages");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT COUNT(*)
* FROM sys.procedures
* WHERE name = 'sp_import_progress';
* -- Expect: 1.
* ===========================================================
*/
}
}
Expected output
What dotnet run printed when the sample was verified, on a freshly created sample schema. Ids differ when the tables already hold rows.
> 1. The messages, in order
0 imported 250 of 1000 rows
0 imported 500 of 1000 rows
0 imported 750 of 1000 rows
0 imported 1000 of 1000 rows
0 a large import: 1000 rows
> 2. Not collected
0 messages