TECH

November 27, 2024

Responsive of Bootstrap - Creating Perfect Websites for All Devices

First of all, let's find out what responsive design is. Responsive Web Design (RWD) is an approach to web design that enables websites to automatically adjust and optimize the user experience across a variety of devices, including desktops, tablets, and mobile phones. In today’s digital age, having a responsive website is crucial.

View More
TECH

November 26, 2024

Introducing Pinia: A Simple State Management Tool for Vue.js

In the world of front-end development, managing state is important for creating scalable and easy-to-maintain applications. As Vue.js grows in popularity, developers look for tools that make their work easier. That’s where Pinia comes in—a modern state management library made for Vue 3. In this blog post, we’ll explain Pinia, its main features, how it compares to Vuex, and how it can help you in your Vue.js projects.

What is Pinia?

Pinia is a state management library that serves as a lightweight and easy-to-use alternative to Vuex, the main state management tool for Vue.js. Pinia is designed for Vue 3 and uses the Composition API, making it a more modern choice for developers. It offers many features that meet the needs of today’s web development.

Key Features of Pinia

  1. Simplicity and Ease of Use

    Pinia stands out because it is simple to use. The API is designed to be user-friendly so that developers can create their stores with very little code. This makes it easy for both new and experienced developers to get started quickly.

  2. Vue 3 Compatibility

    Pinia is built specifically for Vue 3, meaning it works perfectly with the Composition API. This gives developers more flexibility in how they structure their applications and makes state management fit better within Vue.

  3. TypeScript Support

    As TypeScript becomes more common in projects, Pinia offers great support for it. This ensures that developers can catch errors before the code runs, which leads to stronger applications.

  4. Global State Management

    With Pinia, managing the global state is simple. You can create stores that hold your application’s state and access them from any component, making it easier to manage data without passing it through many layers.

  5. Plugin Support

    Pinia allows the use of plugins, which means developers can add more features as needed. This makes Pinia adaptable for various projects.

Comparing Pinia and Vuex

While Vuex has been the main choice for state management in Vue.js, Pinia offers some advantages that make it a good alternative:

  1. API Design
    • Vuex: Uses a more complex approach with mutations, actions, and getters, which can require more code.
    • Pinia: Simplifies state management by combining state, actions, and getters in one store definition.
  2. Integration with Vue 3
    • Vuex: Has a version for Vue 3 but was originally made for Vue 2, which can complicate things.
    • Pinia: Built from the start for Vue 3, ensuring easy integration and better use of the Composition API.
  3. TypeScript Support
    • Vuex: Provides TypeScript support but can be tricky to set up.
    • Pinia: Offers excellent TypeScript support right away, making it easier to use in TypeScript projects.
  4. Performance
    • Vuex: Can be heavier and slower due to its structure.
    • Pinia: Lightweight and optimized for performance, leading to faster state management.

Getting Started with Pinia

To start using Pinia, you’ll first need to install it in your Vue 3 project:

npm install pinia

Once installed, you can create a store like this:

import { defineStore } from 'pinia';

export const useMainStore = defineStore('main', {

   state: () => ({

       count: 0,

   }),

   actions: {

      increment() {

         this.count++;

      },

   },

});

You can then use this store in your components:

<template>

   <div>

      <p>{{ count }}</p>

      <button @click="increment">Increment</button>

   </div>

</template>

<script setup>

import { useMainStore } from '@/stores/main';

const store = useMainStore();

const { count, increment } = store;

</script>


Conclusion

Pinia is a big step forward in state management for Vue.js applications. With its easy-to-use API, strong TypeScript support, and smooth integration with Vue 3, it’s a great choice for developers who want to simplify their work.

While Vuex has been helpful for many years, Pinia’s simplicity and performance make it a strong alternative. Whether you’re working on a small project or a large one, Pinia can help you manage state more effectively.

If you haven’t tried Pinia yet, now is a great time to explore what it can do for your Vue.js projects!

References

View More
TECH

November 26, 2024

Design Patterns with Modern C++

Design patterns are tried-and-tested solutions to common software design problems. With the advent of modern C++ (C++11 and later), these patterns can be implemented more elegantly and efficiently, taking advantage of language features like lambda functions, smart pointers, and threading support. In this article, we'll explore three popular design patterns—Singleton, Observer, and Factory Pattern—and see how they can be applied using modern C++.

1. Singleton Pattern

Purpose

The Singleton pattern ensures that a class has only one instance and provides a global point of access to it.

Modern C++ Implementation

Using C++11's thread-safe static initialization, the Singleton pattern becomes simpler and safer to implement.

Results:

Key Points:

  1. The static local variable ensures thread-safe initialization.
  2. Copy constructor and assignment operator are deleted to prevent multiple instances.

Advantages with Modern C++

  • Simpler syntax compared to manual double-checked locking.
  • Thread-safety is guaranteed out of the box.

2. Observer Pattern

Purpose

The Observer pattern allows an object (subject) to notify multiple dependent objects (observers) about changes in its state.

Modern C++ Implementation

Using std::function and std::vector makes it easier to manage observers and their callbacks.

Results:

Key Points:

  1. std::function allows for flexible observer callbacks.
  2. Lambda expressions simplify observer registration.

Advantages with Modern C++

  • Cleaner and more flexible observer management.
  • Lambdas reduce boilerplate code.

3. Factory Pattern

Purpose

The Factory pattern provides an interface for creating objects without specifying their concrete classes.

Modern C++ Implementation

With smart pointers and std::unordered_map, factories in modern C++ can be made both safe and efficient.

Results:

Key Points:

  1. std::make_unique ensures memory safety and exception handling.
  2. std::unordered_map and lambdas make product registration intuitive.

Advantages with Modern C++

  • Memory management is simplified with smart pointers.
  • Extending the factory is straightforward by adding new lambdas.

Conclusion

Modern C++ features such as smart pointers, lambda expressions, and thread-safe static initialization significantly enhance the implementation of traditional design patterns. They not only make the code more concise and readable but also reduce common pitfalls like memory leaks and thread-safety issues.

Exploring design patterns with modern C++ is an excellent way to understand the power of the language while adhering to best practices in software engineering. By combining these patterns with the features introduced in C++11 and beyond, developers can write more robust, efficient, and maintainable code.

References:

https://www.geeksforgeeks.org/singleton-pattern-c-design-patterns/

https://www.geeksforgeeks.org/factory-method-pattern-c-design-patterns/

https://www.geeksforgeeks.org/observer-pattern-c-design-patterns/

View More
TECH

November 26, 2024

Introduction to Multithreading in C++

Multithreading is an important aspect of modern software development, enhancing performance and optimizing the use of system resources. In the C++ programming language, the ability to create and manage threads is facilitated by the standard library std::thread. In this article, we will explore the basic concepts of multithreading in C++, along with its practical applications and the benefits it offers.

1. Basic Concepts of Multithreading in C++

Multithreading is a technique that allows a program to perform multiple tasks simultaneously, utilizing CPU cores and system resources.

Today, many applications use multithreading, such as image processing and data handling applications. In C++, threads are created through the standard C++ library, std::thread. Each thread in C++ is executed independently and can perform different tasks.

2. Using Multithreading in C++: Applications and Benefits

Using multithreading to design and develop applications based on C++ offers many benefits, including:

  • Increased Performance: Tasks can be executed in parallel, reducing waiting times and speeding up program execution.
  • Workload Division: Large tasks can be divided into smaller ones and assigned to different threads to maximize system resource utilization.
  • Concurrent Responsiveness: The program can handle simultaneous requests from users or different data sources without freezing or slowing down

For a programming language that can leverage many resources like C++, using multithreading is extremely beneficial. This is especially true in the development of applications related to embedded systems, where hardware resources are often significantly limited. Additionally, multithreading is used in image processing and analysis, where it can speed up image rendering and maximize computer resources.

For complex computations such as creating 3D images or simulating systems, using multithreading can make the computation and simulation processes faster.

3. Using multithreading in C++ source code

In C++, threads are managed by the std::thread class. To use this class, you need to include the thread header file. To create a thread, we use the statement: std::thread thread_obj(callable);

When executing the above statement, a thread will be created and will execute the [callable] function. The [callable] can be any of the five ways:

  • Launching Thread Using Function Pointer:
    • Example:

  • Launching Thread Using Lambda Expression
    • Example:

  • Launching Thread Using Non-Static Member Function
    • Example:

  • Launching Thread Using Static Member Function
    • Example:

The above is an example to help you use basic multithreading. When using multithreading, you should pay attention to the following points to avoid data conflicts between threads:

  1. Avoid Race Conditions
  2. Deadlocks
  3. Atomic Operations
  4. Condition Variables
  5. Resource management
  6. Thread Safety
  7. Use thread-safe data structures
  8. Avoid over-subscription

4. Conclusion

Multithreading in C++ is an important technique for optimizing performance and efficiently utilizing system resources. However, using multithreading also requires solid knowledge of synchronization methods and resource management. I hope this article has provided you with an overview of this topic and encouraged you to further explore multithreading in C++.

References:

  1. https://www.geeksforgeeks.org/multithreading-in-cpp/
  2. https://techdifferences.com/difference-between-multiprocessing-and-multithreading.html
  3. https://www.linkedin.com/pulse/choice-between-multithreading-multi-processing-when-use-deepak-kumar-uxyvf
  4. https://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm
View More
TECH

November 20, 2024

Event Handling in C++

Event handling is a critical aspect of modern programming, especially in interactive applications such as GUI software, games, and real-time systems. While C++ lacks built-in event-handling mechanisms, its flexibility allows developers to design efficient systems or leverage powerful libraries like Qt and wxWidgets.

This guide will take you through the essentials of event handling in C++, covering fundamental concepts and practical implementations.

1. What is Event Handling?

Event handling involves responding to actions or events within a program. Examples of events include:

  • A user clicking a button.
  • Moving the mouse or entering keyboard input.
  • A signal triggered within the program.

Unlike some other programming languages with built-in support for event handling, C++ requires developers to design their own systems or utilize external libraries.

2. Key Components of an Event-Handling System

2.1. Event

An event represents an action or signal triggered by a user or the system, such as:

  • A mouse click (MouseClickEvent).
  • A key press (KeyPressEvent).

2.2. Event Listener

An event listener monitors and detects specific events, taking appropriate actions when they occur.

2.3. Event Handler

An event handler is the function or code block executed in response to an event.

3. Building a Basic Event-Handling System in C++

3.1. Using Callback Functions

Callback functions are one of the simplest methods for handling events in C++.

Example:

Explanation:

  • onButtonClick is the event handler function.
  • triggerEvent invokes the callback function when the event occurs.

3.2. Implementing the Observer Pattern

The Observer Pattern is a design pattern where one object (Observer) reacts to changes or events from another object (Subject).

Example:

Explanation:

  • Observer: An interface for defining objects that listen for events.
  • Subject: Manages a list of observers and notifies them when an event occurs.

4. Advantages and Disadvantages of Event Handling in C++

Advantages:

  • Flexibility: Customizable event-handling systems tailored to specific needs.
  • Performance: Well-designed systems can achieve high efficiency.

Disadvantages:

  • Complexity: Building systems from scratch can be challenging.
  • No Built-in Support: Relies on external libraries or design patterns.

5. Real-World Applications

5.1. Game Development

Game engines like Unreal Engine (built with C++) use event-driven models to handle user inputs and game logic.

5.2. GUI Programming

Libraries such as Qt, wxWidgets, and FLTK enable developers to create responsive graphical applications with event handling.

6. Conclusion

Event handling is a foundational concept in programming, enabling applications to react dynamically to user or system actions. While C++ lacks native support, you can utilize strategies like callback functions, the Observer Pattern, or libraries like Qt to implement robust systems.

View More
TECH

November 20, 2024

What is database deadlock?

Deadlock is an important challenge for programmers in navigating the complexity of database systems, as it has the potential to cause system errors and hinder overall performance. The likelihood of deadlock increases in multi-user environments, where multiple transactions compete for shared resources. For developers, understanding the concept and meaning of deadlock is very important. By understanding the mechanisms underlying deadlock, developers can proactively implement strategies to prevent or mitigate its occurrence, thereby ensuring the reliability and efficiency of database operations.
 

What is database deadlock?

In the context of a database, a deadlock occurs when two or more transactions are unable to proceed because each transaction is waiting for a resource that is held by another transaction. This creates a cyclic dependency, where none of the transactions can proceed, leading to a deadlock situation. Deadlocks are a common concurrency issue in database systems where multiple transactions may concurrently access and modify shared resources, such as database rows or tables.
 
Here's a more detailed explanation of a deadlock in a database:
Concurrency: Database systems allow multiple transactions to execute concurrently to improve system performance and throughput.
 
Transactions: In SQL, transactions are sequences of SQL statements that are executed as a single unit of work. Transactions typically consist of multiple SQL statements that read or modify data in a database.
 
Locking: When a transaction reads or modifies data in a database, it acquires locks on the relevant database objects (e.g., rows, tables) to prevent other transactions from accessing the same data concurrently.
 
Deadlock example.
 
Let's consider a simple example involving two transactions, Transaction A and Transaction B, both trying to update two different rows in the same database table:
Transaction A:
Acquires a lock on Row 1.
Attempts to acquire a lock on Row 2.

Transaction B:
Acquires a lock on Row 2.
Attempts to acquire a lock on Row 1.
Now, both transactions are waiting for each other to release the locks on the rows they need. This creates a circular dependency, leading to a deadlock where neither transaction can make progress.
 
Causes of deadlock in database
 
Resource Greed (Hold and Wait): Transactions acquire resources and hold onto them while waiting to acquire additional resources. If transactions hold resources without releasing them, it can lead to deadlock as other transactions may be blocked from acquiring the needed resources.

Circular Dependencies: Transactions are stuck in a circular chain of dependencies, where each transaction is waiting for a resource held by another transaction in the loop. This creates a situation where none of the transactions can proceed, resulting in a deadlock.

Poor Planning: Inadequate transaction planning or scheduling can lead to conflicts between transactions, causing deadlocks. Transactions may request resources in an incompatible order or without considering potential conflicts with other transactions.

Lock Mismanagement: Improper or inefficient use of locks by transactions can contribute to deadlocks.

Lack of Deadlock Detection and Handling Mechanism: It means the system does not have a built-in mechanism to identify and resolve deadlocks automatically.
 
The consequences and risks when deadlock occurs
 
Deadlock is a serious challenge for developers and can have significant consequences if not resolved properly. Here's why:
System Failure: Deadlocks can lead to system failures where transactions are unable to proceed, causing the system to become unresponsive or crash. If deadlocks occur frequently or involve critical transactions, they can severely impact the availability and reliability of the database system.

Performance Impact: Deadlocks can cause performance degradation in database systems by introducing delays and resource contention. When transactions are deadlocked, system resources are tied up waiting for the deadlock to be resolved, resulting in decreased throughput and slower response times for other transactions.

Data Integrity Risks: In addition to system failures and performance impacts, deadlocks pose risks to data integrity. If transactions involved in a deadlock are terminated or rolled back to resolve the deadlock, it can lead to data inconsistencies or loss of updates, potentially compromising the integrity of the database.

Necessary Conditions for Deadlock
 
Mutual Exclusion: At least one resource must be held in a non-shareable mode, meaning only one process can use the resource at a time. This condition ensures that when a transaction holds a lock on a resource, no other transaction can access it until the lock is released.

Hold and Wait: A transaction must hold at least one resource and be waiting to acquire additional resources that are currently held by other transactions. This condition implies that transactions can acquire resources incrementally, holding some while waiting for others.

No Preemption: Resources cannot be forcibly taken away from transactions. In other words, once a transaction holds a resource, it cannot be preempted or forcibly released by the system to allow another transaction to proceed. Transactions must voluntarily release the resources they hold.

Circular Wait: There must be a circular chain of two or more transactions, each waiting for a resource held by the next transaction in the chain. This condition implies that Transaction A is waiting for a resource held by Transaction B, Transaction B is waiting for a resource held by Transaction C, and so on, until Transaction N is waiting for a resource held by Transaction A, completing the circular chain.
 
How to prevent deadlock?
 
Deadlocks in databases can lead to system slowdowns, application freezes, or even system crashes if not properly managed. Therefore, developers should need to have knowledge about deadlocks to implement preventive measures such as proper transaction design, lock management, and concurrency control to minimize the occurrence of deadlocks in database systems.

Minimizing the possibility of deadlocks in the database is necessary. To prevent deadlock, we can implement one of the following solutions:

Implement Retry Mechanisms: Design applications to handle deadlock situations gracefully by implementing retry mechanisms. When a transaction encounters a deadlock, it can automatically retry the operation after a brief delay, allowing the deadlock to resolve naturally without manual intervention, maintaining data consistency, and optimizing system resources.

Example:
 
<?php
function place_order($order_id) {
    $max_retries = 3;
    $retry_count = 0;

 

    while ($retry_count < $max_retries) {
        try {
// Attempt to deduct item quantity from inventory
            deduct_inventory($order_id);

 

// Attempt to update order status
            update_order_status($order_id, 'Processed');

 

            echo "Order $order_id placed successfully.";
            return;
        } catch (DeadlockException $e) {
            echo "Deadlock detected. Retrying order $order_id";
            sleep(1); //Set delay time before retrying
            $retry_count++;
        }
    }
    echo "Failed to place order $order_id after $max_retries retries.";
}

 

function deduct_inventory($order_id) {
// Deduct item quantity from inventory
    // This operation may encounter a deadlock due to concurrent access
}

 

function update_order_status($order_id, $status) {
// Update order status in the database
    // This operation may encounter a deadlock due to concurrent access
}
 
place_order(1001);
?>
In this example, the place_order function attempts to place an order by deducting the item quantity from the inventory and updating the order status. If a deadlock occurs during these operations, the function retries the transaction up to a maximum number of times before giving up. This ensures that the order is eventually processed, even in the presence of deadlock situations.

Optimize Transaction Ordering: When performing multiple operations within a transaction, order the operations in a consistent and predictable manner to minimize the risk of deadlock scenarios.
 
Conclusion
 
Knowledge about deadlocks in databases is necessary for developers to ensure the performance, stability, and reliability of database systems and applications. By understanding how deadlocks occur, implementing best practices for deadlock prevention and resolution, and incorporating deadlock handling mechanisms into their designs and code, developers can effectively manage and mitigate the risks associated with deadlocks in database environments.
 
References:
 
 
 
View More
TECH

November 20, 2024

Leveraging AWS S3 in Laravel: A Simple Guide

Amazon Web Services (AWS) Simple Storage Service (S3) is a strong and dependable option for file management and storage. Easily integrate S3 for file storage with Laravel, one of the most popular PHP frameworks. Even if you're not familiar with using AWS S3 in Laravel, this blog will walk you through the process step by step.
 

What is AWS S3?

 

AWS S3 is a cloud storage service provided by Amazon Web Services (AWS). It offers object storage with a simple web interface to store and retrieve any amount of data at any time.
S3 is designed to deliver durability, making it an ideal choice for storing critical data and backups.
 

Why Use AWS S3 in Laravel?

 

Laravel, a popular PHP framework, integrates well with AWS S3 to handle file uploads and storage. Storing files locally may not be efficient in large-scale applications, and AWS S3 offers advantages over local storage

-  Scalability: As your app grows, S3 scales effortlessly.
-  Security: AWS provides strong encryption and access control features.
-  Backup & Recovery: S3 offers easy backup and recovery options.
-  Cost-Effective: You only pay for what you store, making it affordable for projects of all sizes.
 

Configuring AWS S3 Storage in Laravel

 

Step 1: Install AWS SDK in Laravel

 

First, make sure your Laravel app is set up and running. To use S3, we need to install the AWS SDK (Software Development Kit). Luckily, Laravel makes it easy. Run the following command in your terminal:
 
composer require league/flysystem-aws-s3-v3
This installs the necessary package to work with AWS S3 in Laravel.
 

Step 2: Set Up the AWS S3 Account

 

If you don’t already have an AWS account, you’ll need to create one at https://aws.amazon.com. Once logged in:
 
1. Search for "S3" in the services menu.
2. Create a new S3 bucket. A bucket is simply a container to hold your files.
3. Note down your Bucket Name, Access Key, and Secret Key—you’ll need these later.
 

Step 3: Configure Your Laravel App for S3

 

Laravel’s configuration files are where you connect the app to S3. Open your .env file and edit the value of following lines:
 
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_DEFAULT_REGION=your-region
AWS_BUCKET=your-bucket-name
 
Make sure to replace your-access-key, your-secret-key, your-region, and your-bucket-name with the details from your AWS account. The AWS_DEFAULT_REGION is usually something like us-east-1 or eu-west-1.
 

Basic usage with AWS S3

 

Upload Files to S3

 

With the setup complete, you can now upload files to your S3 bucket. Laravel’s file storage functions work seamlessly with S3.
Here’s an example of how to upload a file:
 
use Illuminate\Support\Facades\Storage;
public function uploadFile(Request $request)
{
    if ($request->hasFile('file')) {
        $file = $request->file('file');
        $path = $file->store('uploads', 's3'); // 'uploads' is the folder in your bucket
    
        // Make the file publicly accessible
        Storage::disk('s3')->setVisibility($path, 'public');

 

        return "File uploaded to: " . $path;
    }
    return "No file selected.";
}
 
In this example, we check if the file exists, then upload it to the uploads folder in the S3 bucket. The setVisibility method ensures the file is publicly accessible.
 

Access Files from S3

 

To access the uploaded files, you can generate URLs directly from the S3 bucket. Here’s how:
 
$url = Storage::disk('s3')->url('uploads/your-file-name.jpg');
return $url;
 
This gives you the file's URL so you can display it in your app.
 

Deleting Files from S3

 

Deleting files from S3 is just as easy as uploading. You can remove a file using:
 
Storage::disk('s3')->delete('uploads/your-file-name.jpg');
 

Advanced Features (Optional)

 

S3 offers many advanced features, but you don’t have to use them right away. As you get more comfortable, you can explore options like:
-  Versioning: Keep track of file versions.
-  Access Control: Set up more detailed access permissions for your files.
-  Lifecycle Rules: Automatically delete or archive files after a certain period.
 

Conclusion

 

Integrating AWS S3 with Laravel can significantly enhance your file storage capabilities, giving your application scalability, security, and cost-efficiency. Following this guide, you can easily upload, access, and manage files on AWS S3 from your Laravel application.
With AWS S3, you no longer have to worry about running out of storage space or managing complex file systems. You can focus on building your application while AWS takes care of the rest.
 

Reference

View More
TECH

November 20, 2024

EC2 Access to S3 Without Access Key and Secret Key.

If you are using AWS services, specifically EC2 and S3. In the usual way, if you want to access from EC2 to S3 to read and write data, you need to use two pieces of information: the access key and secret key.

These two pieces of information are usually stored in the source code or somewhere on the EC2 instance. This approach carries a risk of information leakage, and if hackers obtain these keys, it could result in a loss of data on S3 bucket.

If you do not want to hardcode these keys, you can use an IAM role to grant the necessary permissions to the EC2 instance to access the S3 bucket.
To set this up, you would create an IAM role with permissions to access the S3 bucket and then attach that role to the EC2 instance. Afterward, the EC2 instance can use the role’s temporary security credentials to access the S3 bucket.

Here are the detailed steps to do it.

Step 1: Create an IAM Role for the EC2 Instance

1. Access IAM on the AWS Console.
2. Go to Roles and click Create Role.
3. In the Trusted entity section, select AWS service and select EC2 because this role will be assigned to an EC2 instance.
4. In the Permissions section:

    - Select AmazonS3FullAccess or create a separate policy if you want to allow access to only a specific bucket.
    - If you want to create your own policy, you can select Create policy and use the following JSON to specify access to a specific bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::your-bucket-name/*"
         }
    ]
}

5. Confirm and name the role, for example EC2S3AccessRole.

Step 2: Assign IAM Role to EC2 Instance

1. Go to EC2 Console and select the instance you want to assign permissions to.
2. On the Actions tab, select Security > Modify IAM role.
3. Select the EC2S3AccessRole role you created in the step above and confirm.

Step 3: Example upload images from EC2 to S3

With the IAM Role assigned, the EC2 instance will have access to S3 without using the Access Key or Secret Key. Here is an example Python code to upload images from EC2 to S3:

1. Install boto3 if not already present:

pip install boto3

2. Write Python code to upload images to S3:

import boto3

# Initialize S3 client
s3 = boto3.client('s3')

# Define bucket and file name
bucket_name = 'your-bucket-name'
file_path = '/path/to/your/image.jpg'
s3_key = 'uploads/image.jpg' # Path on S3

# Upload file
try:
    s3.upload_file(file_path, bucket_name, s3_key)
    print("Upload successful!")
except Exception as e:
    print("An error occurred:", e)

Note:
    - IAM Role ensures access only from the assigned EC2 instance without using a direct key.
    - If you need more specific permissions, adjust the policy to suit your needs.

Conclusion

Using IAM Roles helps to enhance security and eliminate risks associated with managing and transmitting Access Keys and Secret Keys. Hopefully the above guide will help you easily deploy and secure your system when uploading data from EC2 to S3 bucket.

References:

View More
TECH

November 18, 2024

Repository pattern in C#

The Repository Pattern is a design pattern used to abstract data access logic, providing a clean separation between the business logic and data access layers in an application. By implementing this pattern, you encapsulate data access logic in a repository class that acts as an intermediary between the business logic and the data source (like a database, web service, or API).

 

In C#, the Repository Pattern helps to centralize data access logic and makes it easier to swap out different data sources (e.g., switching from an SQL database to a NoSQL database) without affecting the rest of the application. It also simplifies testing by allowing mock repositories to be used instead of actual data sources.

1. Components of the Repository Pattern

Entity: A class that represents the model of the data being stored in the database (e.g., Company, Customer..).

Repository Interface: Defines the contract for how data access operations are handled.

Repository Implementation: Implements the data access logic, such as querying the database.

Business Logic: The service layer or business rules of the application.

2. Example of the Repository Pattern in C#

Step 1: Define the Entity
Let's start with an entity class representing a Customer.
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Step 2: Create the Repository Interface
The repository interface defines the contract that all repository classes must implement. It usually includes methods for basic CRUD (Create, Read, Update, Delete) operations.
public interface ICustomerRepository
{
    IEnumerable GetAll();
    Product GetById(int id);
    void Add(Customer customer);
    void Update(Customer customer );
    void Delete(int id);
}
Step 3: Implement the Repository
In this step, you create the concrete repository class that implements the interface. Here’s an example using Entity Framework as the data access technology.
public class CustomerRepository : ICustomerRepository
{
    private readonly EntitiesDbContest _context;

    public CustomerRepository(EntitiesDbContest context)
    {
        _context = context;
    }

    public IEnumerable GetAll()
    {
        return _context.Customers.ToList();
    }

    public Customer GetById(int id)
    {
        return _context.Customers.Find(id);
    }

    public void Add(Customer customer)
    {
        _context.Customers.Add(customer);
        _context.SaveChanges();
    }

    public void Update(Customer customer)
    {
        _context.Customers.Update(customer);
        _context.SaveChanges();
    }

    public void Delete(int id)
    {
        var Customer = _context.Customers.Find(id);
        if (Customer != null)
        {
            _context.Customers.Remove(Customer);
            _context.SaveChanges();
        }
    }
}
Step 4: Using the Repository:
public class ProductService
{
    private readonly IProductRepository _productRepository;

    public ProductService(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IEnumerable GetProducts()
    {
        return _productRepository.GetAll();
    }

    public void AddProduct(Product product)
    {
        _productRepository.Add(product);
    }

    // Additional service methods can be added as needed
}

3. Benefits of the Repository Pattern

Ease of Testing: Interfaces allow for easy mocking, making unit testing more straightforward. Code Reusability: Common data access logic is centralized in the repository. Maintenance: Changes in data access logic (e.g., switching from SQL Server to MongoDB) require changes in only one place. Support for Multiple Data Sources: Different implementations can be created for different data sources while maintaining the same interface.

Conclusion

The Repository Pattern is an effective way to decouple business logic from data access in C# applications. It makes the code more maintainable, testable, and scalable. By abstracting the data access layer, the repository pattern promotes cleaner and more organized architecture, especially when working with complex systems where data access logic can become tangled with business logic. In modern applications, especially those built with ASP.NET Core, using the Repository Pattern along with Dependency Injection and Entity Framework results in a robust and flexible architecture that is easier to manage in the long term.

View More
TECH

November 18, 2024

Web Programming Series - Client-Side Rendering (CSR)

Besides SSR, we also have a newer concept, which is CSR. And today I will share about CSR (Client-Side Rendering).
This is also an important area of knowledge in web development.
The article will provide insights into how CSR works, its strengths, and its limitations.
Let's get started...

View More
1 4 5 6 7 8 16