Running DotNet applications as a service in macOS

Running DotNet applications as a service in macOS

Running an application as a service in macOS can be accomplished using a tool called launchd. launchd is a system-wide daemon manager that is built into macOS. It can be used to run applications automatically at startup, or on a schedule. In this article, we’ll show you how to run an application as a service using launchd, and explain the difference between LaunchDaemons and LaunchAgents.

Step 1: Create a launchd plist file The first step in running an application as a service using launchd is to create a property list file called a “launchd plist”. This file defines the service and its settings, including the name, program to run, and any environment variables or other settings. The plist file is an XML file and should have the extension .plist. An example of a plist file is the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.myservice</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/your/program</string>
    </array>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Step 2: Copy the plist file to the appropriate directory Once the plist file is created, you will need to copy it to the appropriate directory. There are two main directories for launchd plist files: /Library/LaunchDaemons/ and /Library/LaunchAgents/.

The difference between LaunchDaemons and LaunchAgents is that LaunchDaemons are used to run background services that do not require a user to be logged in, while LaunchAgents are used to run applications that are associated with a specific user account.

For example, if you want to run a service that starts automatically at boot time and runs in the background, you would copy the plist file to /Library/LaunchDaemons/. If you want to run an application that starts automatically when a user logs in, you would copy the plist file to /Library/LaunchAgents/.

Step 3: Load the service Once the plist file is in the appropriate directory, use the launchctl command to load the service. For example:

sudo launchctl load /Library/LaunchDaemons/com.example.myservice.plist

Step 4: Verify that the service is running You can use the launchctl command to check the status of the service:

launchctl list

This will show all the services that are currently running, and their status.

In summary, launchd is a powerful tool built into macOS that allows you to run applications as services. To use launchd, you need to create a plist file that defines the service and its settings, then copy it to the appropriate directory, and load it using the launchctl command. The difference between LaunchDaemons and LaunchAgents is that the former are used to run background services that do not require a user to be logged in, while the latter are used to run applications that are associated with a specific user account.

Entity Framework Core & lazy loading

Entity Framework Core & lazy loading

In Entity Framework 7, lazy loading is a technique used to delay the loading of related entities until they are actually needed. This can help to improve the performance of an application by reducing the amount of data that is retrieved from the database upfront.

To implement lazy loading in EF7, the “virtual” modifier is used on the navigation properties of an entity class. Navigation properties are used to represent relationships between entities, such as one-to-many or many-to-many.

For example, consider the following code snippet for a “Course” entity class and a “Student” entity class in EF7, with a one-to-many relationship between them:

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public virtual ICollection<Student> Students { get; set; }
}

public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int CourseId { get; set; }
    public virtual Course Course { get; set; }
}

 

In this example, the “Students” navigation property in the “Course” class and the “Course” navigation property in the “Student” class are both marked as “virtual”. This allows EF7 to override these properties with a proxy at runtime, enabling lazy loading for the related entities.

To use lazy loading in an EF7 application, the “DbContext.LazyLoadingEnabled” property must be set to “true”. When lazy loading is enabled, related entities will not be loaded from the database until they are actually accessed.

For example, the following code demonstrates how lazy loading can be used to retrieve a list of courses and their students:

using (var context = new SchoolContext())
{
    context.LazyLoadingEnabled = true;
    var courses = context.Courses.ToList();
    foreach (var course in courses)
    {
        Console.WriteLine("Course: " + course.CourseName);
        foreach (var student in course.Students)
        {
            Console.WriteLine("Student: " + student.FirstName + " " + student.LastName);
        }
    }
}

In this code, the list of courses is retrieved from the database and stored in the “courses” variable. The students for each course are not retrieved until they are accessed in the inner loop. This allows the application to retrieve only the data that is needed, improving performance and reducing the amount of data transferred from the database.

Lazy loading can be a useful tool for optimizing the performance of an EF7 application, but it is important to consider the trade-offs and use it appropriately. Lazy loading can increase the number of database queries and the overall complexity of an application, and it may not always be the most efficient approach.

 

5 Good Practices for Integration Testing with NUnit

5 Good Practices for Integration Testing with NUnit

Integration tests are a crucial part of any software development process, as they help ensure that different parts of a system are working together correctly. When writing integration tests, it is important to follow best practices in order to ensure that your tests are effective and maintainable. Here are a few good practices for integration testing using NUnit:

  1. Use test fixtures: NUnit provides a concept called “test fixtures,” which allow you to set up and tear down common resources that are needed by multiple test cases. This can help reduce duplication and make your tests more maintainable.
    [TestFixture]
    public class DatabaseTests
    {
        private Database _database;
    
        [SetUp]
        public void SetUp()
        {
            _database = new Database();
        }
    
        [TearDown]
        public void TearDown()
        {
            _database.Dispose();
        }
    
        [Test]
        public void Test1()
        {
            // test code goes here
        }
    
        [Test]
        public void Test2()
        {
            // test code goes here
        }
    }
    

     

  2. Use setup and teardown methods: In addition to test fixtures, NUnit also provides setup and teardown methods that can be used to perform common tasks before and after each test case. This can be helpful for setting up test data or cleaning up after a test.
    [TestFixture]
    public class DatabaseTests
    {
        private Database _database;
    
        [SetUp]
        public void SetUp()
        {
            _database = new Database();
        }
    
        [TearDown]
        public void TearDown()
        {
            _database.Dispose();
        }
    
        [SetUp]
        public void TestSetup()
        {
            // setup code goes here
        }
    
        [TearDown]
        public void TestTeardown()
        {
            // teardown code goes here
        }
    
        [Test]
        public void Test1()
        {
            // test code goes here
        }
    
        [Test]
        public void Test2()
        {
            // test code goes here
        }
    }
    

     

  3. Use test cases: NUnit allows you to specify multiple test cases for a single test method using the TestCase attribute. This can help reduce duplication and make it easier to test different scenarios.
    [TestFixture]
    public class CalculatorTests
    {
        [TestCase(1, 2, 3)]
        [TestCase(10, 20, 30)]
        [TestCase(-1, -2, -3)]
        public void TestAdd(int x, int y, int expected)
        {
            Calculator calculator = new Calculator();
            int result = calculator.Add(x, y);
            Assert.AreEqual(expected, result);
        }
    }
    

     

  4. Use the Assert class: NUnit provides a variety of assertions that can be used to verify the behavior of your code. It is important to use these assertions rather than manually checking for expected results, as they provide better error messages and make it easier to debug test failures.
    [TestFixture]
    public class CalculatorTests
    {
        [Test]
        public void TestAdd()
        {
            Calculator calculator = new Calculator();
            int result = calculator.Add(1, 2);
            Assert.AreEqual(3, result);
        }
    
        [Test]
        public void TestSubtract()
        {
            Calculator calculator = new Calculator();
            int result = calculator.Subtract(10, 5);
            Assert.AreEqual(5, result);
        }
    }
    

     

  5. Use test categories: NUnit allows you to categorize your tests using the Category attribute. This can be helpful for organizing your tests and selectively running only certain categories of tests.
    [TestFixture]
    public class DatabaseTests
    {
        [Test]
        [Category("Database")]
        public void Test1()
        {
            // test code goes here
        }
    
        [Test]
        [Category("Database")]
        public void Test2()
        {
            // test code goes here
        }
    
        [Test]
        [Category("API")]
        public void Test3()
        {
            // test code goes here
        }
    }
       
    

     

By following these best practices, you can write integration tests that are effective, maintainable, and easy to understand. This will help you ensure that your code is working correctly and reduce the risk of regressions as you continue to develop and evolve your system.