Best Practices
Follow these best practices to build robust, efficient applications with the Eriksson Beam API.
Connection Management
Always Use using Statements
Ensure proper cleanup of resources:
// Recommended: using statement
using var launcher = await ErikssonBeamLauncher.LaunchErikssonBeam(args);
var client = launcher.Client;
// Resources automatically cleaned up
// Alternative: try-finally
var client = await ErikssonBeamFinder.GetFirstSupportedBeamClient(args);
try
{
// Work with client
}
finally
{
client.Dispose();
}
Handle the 10-Minute Timeout
Eriksson Beam stops listening for API connections after 10 minutes:
// If connection fails, prompt user to restart
try
{
var client = await ErikssonBeamFinder.GetFirstSupportedBeamClient(args);
}
catch (ErikssonBeamNotRunningException)
{
Console.WriteLine("Cannot connect. Please restart Eriksson Beam and try again.");
}
Use Health Monitoring for Long-Running Applications
var clientArgs = new ErikssonBeamClientArgs
{
LicenseKey = licenseKey,
ProcessID = processId,
EnableHealthMonitoring = true,
HealthCheckIntervalMs = 5000
};
var client = new ErikssonBeamClient(clientArgs);
client.HealthChanged += (sender, e) =>
{
if (e.NewHealth.Status == ProcessHealthStatus.Crashed)
{
Console.WriteLine("Eriksson Beam crashed! Attempting recovery...");
}
};
Data Operations
Always Pull Before Push
This is critical to avoid data loss:
// CORRECT: Pull preserves existing data
var design = await client.PullBeamDesignerAsync();
design.DesignCriteria.ProjectInformation.DesignerName = "Jane Doe";
await client.PushBeamDesignerAsync("", design);
// WRONG: Direct creation overwrites EVERYTHING
var design = new BeamDesign(); // Don't do this!
design.DesignCriteria.ProjectInformation.DesignerName = "Jane Doe";
await client.PushBeamDesignerAsync("", design); // Data loss!
Batch All Changes Before Pushing
Push operations are expensive. Batch modifications:
// CORRECT: One push
var design = await client.PullBeamDesignerAsync();
design.Property1 = value1;
design.Property2 = value2;
design.Property3 = value3;
design.Property4 = value4;
await client.PushBeamDesignerAsync("", design); // Single push
// WRONG: Multiple pushes (slow!)
design.Property1 = value1;
await client.PushBeamDesignerAsync("", design);
design.Property2 = value2;
await client.PushBeamDesignerAsync("", design);
// ... and so on
Cache Pull Results When Appropriate
If you need to read multiple properties without modification:
// Pull once, read many
var design = await client.PullBeamDesignerAsync();
// Read multiple properties
var projectName = design.DesignCriteria.ProjectInformation.ProjectName;
var designerName = design.DesignCriteria.ProjectInformation.DesignerName;
var sectionType = design.ConcreteExtents?.GetType().Name;
var loadCount = design.StructuralModel.Loading.PointLoads?.Count ?? 0;
// Don't pull again for each property!
Security
Store License Keys Securely
Never hardcode license keys:
// CORRECT: Environment variable
var licenseKey = Environment.GetEnvironmentVariable("ERIKSSON_LICENSE_KEY");
// CORRECT: Configuration file (not in source control)
var licenseKey = Configuration["ErikssonBeam:LicenseKey"];
// WRONG: Hardcoded
var licenseKey = "XXXX-XXXX-XXXX-XXXX"; // Don't do this!
Add Configuration Files to .gitignore
# .gitignore
appsettings.Development.json
appsettings.Local.json
*.user
Error Handling
Use Specific Exception Types
try
{
var design = await client.PullBeamDesignerAsync();
}
catch (ErikssonBeamNotRunningException)
{
// Handle connection issue
}
catch (ServerErrorException ex) when (ex.Response.ResponseCode == ResponseCode.LicenseError)
{
// Handle license issue
}
catch (ServerErrorException ex)
{
// Handle other server errors
}
catch (OperationCanceledException)
{
// Handle timeout
}
Implement Graceful Degradation
public async Task<BeamDesign> GetDesignOrDefault(ErikssonBeamClient client, string project)
{
try
{
return await client.PullBeamDesignerAsync(project);
}
catch (ServerErrorException ex) when (ex.Response.ResponseCode == ResponseCode.InvalidRequest)
{
Console.WriteLine($"Project '{project}' not found");
return null;
}
}
Performance
Process Files in Batches
For multiple files, consider batch sizes:
public async Task ProcessFilesInBatches(string[] files, int batchSize = 5)
{
for (int i = 0; i < files.Length; i += batchSize)
{
var batch = files.Skip(i).Take(batchSize).ToArray();
var args = new ErikssonBeamLauncherArgs
{
LicenseKey = licenseKey,
ExecutablePath = executablePath,
FilesToOpen = batch,
CloseErikssonBeamOnClientDisconnect = true
};
using var launcher = await ErikssonBeamLauncher.LaunchErikssonBeam(args);
foreach (var file in batch)
{
var fileName = Path.GetFileNameWithoutExtension(file);
await ProcessSingleFile(launcher.Client, fileName);
}
}
}
Use Appropriate Timeouts
Adjust timeouts based on operation complexity:
// Quick operations
var quickArgs = new ErikssonBeamConnectionAttemptArgs
{
LicenseKey = licenseKey,
IdleTimeoutMs = 15000 // 15 seconds
};
// Complex operations with large files
var longArgs = new ErikssonBeamConnectionAttemptArgs
{
LicenseKey = licenseKey,
IdleTimeoutMs = 120000 // 2 minutes
};
Logging
Enable Logging for Debugging
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddConsole()
.AddFile("logs/eriksson-beam-{Date}.log")
.SetMinimumLevel(LogLevel.Debug);
});
var logger = loggerFactory.CreateLogger<MyApplication>();
var launcher = await ErikssonBeamLauncher.LaunchErikssonBeam(args, logger);
Log Important Operations
logger.LogInformation("Starting batch processing of {Count} files", files.Length);
foreach (var file in files)
{
logger.LogDebug("Processing file: {FileName}", file);
try
{
await ProcessFile(client, file);
logger.LogInformation("Successfully processed: {FileName}", file);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to process: {FileName}", file);
}
}
Testing
Use Test License Keys in Development
#if DEBUG
// Debug mode may allow TEST_KEY
var licenseKey = "TEST_KEY";
#else
var licenseKey = Environment.GetEnvironmentVariable("ERIKSSON_LICENSE_KEY");
#endif
Create Integration Tests
[Test]
public async Task PullPush_PreservesData()
{
using var launcher = await ErikssonBeamLauncher.LaunchErikssonBeam(testArgs);
var client = launcher.Client;
// Pull original
var original = await client.PullBeamDesignerAsync();
var originalName = original.DesignCriteria.ProjectInformation.ProjectName;
// Modify and push
original.DesignCriteria.ProjectInformation.DesignerName = "Test";
await client.PushBeamDesignerAsync("", original);
// Pull again and verify
var updated = await client.PullBeamDesignerAsync();
Assert.AreEqual(originalName, updated.DesignCriteria.ProjectInformation.ProjectName);
Assert.AreEqual("Test", updated.DesignCriteria.ProjectInformation.DesignerName);
}
See Also
- Error Handling - Exception details
- Common Tasks - Example implementations
- Troubleshooting - Problem resolution