background-shape
feature-image

E-commerce is an increasingly competitive and fast-paced industry, and building a scalable and reliable e-commerce platform is crucial for success. .NET and Azure offer a powerful combination of technologies for building such a platform, providing the tools you need to create a beautiful and intuitive shopping experience, store and manage product data, process payments, fulfill orders, and optimize performance.

In this blog post, we’ll explore how to use .NET and Azure to build a scalable and reliable e-commerce platform, covering the following topics:

  • ASP.NET Core for creating a modern and responsive web application
  • Azure Functions for implementing background tasks and integrating with third-party services
  • Azure Cosmos DB for storing and querying product data
  • Azure Payment Services for integrating with payment gateways
  • Azure Queues for managing the order fulfillment process
  • Azure App Insights for monitoring and optimizing performance
  • Azure AD for securing the application

By the end of this blog post, you’ll have a solid understanding of how to use .NET and Azure to build a scalable and reliable e-commerce platform that can handle the demands of a growing business.

Creating a beautiful and intuitive shopping experience with ASP.NET Core and Azure Functions:

ASP.NET Core is a cross-platform, high-performance, and open-source framework for building modern web applications. It allows you to create responsive and interactive user interfaces using Razor pages, MVC, or web API controllers, and supports a wide range of front-end technologies such as HTML, CSS, and JavaScript.

To create a beautiful and intuitive shopping experience with ASP.NET Core, you can use the following features:

  • Razor pages for creating easy-to-maintain pages with a separation of concerns between markup and code
  • MVC for creating flexible and testable controllers that handle HTTP requests and responses
  • Web API controllers for creating RESTful APIs that can be consumed by mobile apps or other client applications
  • Entity Framework Core for querying and updating data in a database
  • Identity for managing user accounts and authentication

To make your e-commerce application more interactive and responsive, you can also use Azure Functions to implement background tasks and integrate with third-party services. Azure Functions is a serverless compute service that allows you to run small pieces of code in response to triggers such as HTTP requests, timers, or queue messages. You can use Azure Functions to implement a variety of tasks, such as:

  • Sending emails with SendGrid
  • Processing images with Azure Cognitive Services
  • Integrating with payment gateways with Azure Payment Services
  • Sending SMS messages with Twilio

Scalable Ecommerce App

To use Azure Functions with your ASP.NET Core application, you can use the Azure Functions bindings to trigger functions from your code or send data to them. For example, you can use the SendGrid binding to send an order confirmation email when a customer places an order:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using SendGrid.Helpers.Mail;

namespace Ecommerce.Functions
{
    public static class SendOrderConfirmationEmail
    {
        [FunctionName("SendOrderConfirmationEmail")]
        public static void Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] Order order,
            [SendGrid(ApiKey = "SendGridApiKey")] out SendGridMessage message,
            ILogger log)
        {
            message = new SendGridMessage();
            message.From = new EmailAddress("noreply@ecommerce.com", "Ecommerce");
            message.Subject = "Order Confirmation";
            message.AddTo(order.Customer.Email, order.Customer.Name);
            message.AddContent(MimeType.Html, $"<h1>Thank you for your order!</h1><p>"+
            "Your order number is: {order.Id}</p><p>Total amount: {order.Amount}</p>");
        }
    }

    public class Order
    {
        public string Id { get; set; }
        public decimal Amount { get; set; }
        public Customer Customer { get; set; }
    }

    public class Customer
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

To use the SendGrid binding, you will need to specify the SendGrid attribute on the output parameter, and set the ApiKey property to the API key of your SendGrid account. The function will then be triggered when an HTTP POST request is received, and the SendGridMessage object will be sent to SendGrid to be delivered to the specified email address.

Storing and managing product data with Azure Cosmos DB and .NET:

In an e-commerce application, the product catalog is a critical component that needs to be fast, scalable, and reliable. Azure Cosmos DB is a globally distributed, multi-model database service that allows you to store and query data with low latency and high throughput. It offers a number of APIs including SQL, MongoDB, Cassandra, and Azure Table Storage, making it easy to store and query data in the format that best fits your needs.

To store and query product data with Azure Cosmos DB and .NET, you can use the following steps:

  1. Create a Cosmos DB account and database in the Azure portal.
  2. Install the .NET SDK for Cosmos DB in your application.
  3. Define a model class for your products, annotating the properties with the JsonPropertyName attribute to specify the corresponding field names in the database.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Product
{
    [JsonPropertyName("id")]
    public string Id { get; set; }

    [JsonPropertyName("category")]
    public string Category { get; set; }

    [JsonPropertyName("name")]
    public string Name { get; set; }

    [JsonPropertyName("description")]
    public string Description { get; set; }

    [JsonPropertyName("price")]
    public decimal Price { get; set; }
}
  1. Create a service class that uses the .NET SDK for Cosmos DB to create the database and container, and add, update, delete, and query products.

Here is an example of a C# service class that uses the .NET SDK for Cosmos DB to create the database and container, and add, update, delete, and query products:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using Microsoft.Azure.Cosmos;

namespace Ecommerce.Web.Services
{
    public class CosmosDbService
    {
        private readonly CosmosClient _client;
        private readonly Container _container;

        public CosmosDbService(string connectionString, string databaseName, string containerName)
        {
            _client = new CosmosClient(connectionString);
            var database = _client.GetDatabase(databaseName);
            _container = database.GetContainer(containerName);
        }

        public async Task<Product> GetProductAsync(string id)
        {
            try
            {
                ItemResponse<Product> response = await _container.ReadItemAsync<Product>
                (id, new PartitionKey("Electronics"));
                return response.Value;
            }
            catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
            {
                return null;
            }
        }

        public async Task<IEnumerable<Product>> GetProductsAsync(string category)
        {
            var query = _container.GetItemLinqQueryable<Product>()
                .Where(p => p.Category == category)
                .ToFeedIterator();

            List<Product> results = new List<Product>();
            while (query.HasMoreResults)
            {
                results.AddRange(await query.ReadNextAsync());
            }

            return results;
        }

        public async Task AddProductAsync(Product product)
        {
            await _container.CreateItemAsync(product, new PartitionKey(product.Category));
        }

        public async Task UpdateProductAsync(string id, Product product)
        {
            await _container.UpsertItemAsync(product, new PartitionKey(product.Category));
        }

        public async Task DeleteProductAsync(string id)
        {
            await _container.DeleteItemAsync<Product>(id, new PartitionKey("Electronics"));
        }
    }
}

In this example, the CosmosDbService class takes the connection string, database name, and container name as arguments in the constructor.

It uses these to create a CosmosClient object and a Container object, which it uses to perform various operations on the products stored in the database.

The methods include GetProductAsync to retrieve a single product by its ID, GetProductsAsync to retrieve a list of products by category, AddProductAsync to add a new product, UpdateProductAsync to update an existing product, and DeleteProductAsync to delete a product.

Integrating payment processing with Azure Payment Services and .NET:

Accepting payments online is a crucial part of any e-commerce platform. Azure Payment Services is a set of services that allow you to integrate with various payment gateways, enabling you to accept payments from a variety of sources such as credit cards, bank transfers, and digital wallets.

To integrate payment processing with Azure Payment Services and .NET, you can use the following steps:

  1. Create an Azure Payment Services account and configure the payment gateways you want to use.
  2. Install the .NET SDK for Azure Payment Services in your application.
  3. Create a service class that uses the .NET SDK to create payment requests, process payment responses, and handle errors.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using Microsoft.Azure.PaymentServices;
using Microsoft.Azure.PaymentServices.Clients;

namespace Ecommerce.Web.Services
{
    public class PaymentService
    {
        private readonly PaymentClient _client;

        public PaymentService(string connectionString)
        {
            _client = new PaymentClient(connectionString);
        }

        public async Task<PaymentRequest> CreatePaymentRequestAsync(string gatewayId, 
        decimal amount, string currency, string customerId, string returnUrl, string cancelUrl)
        {
            var request = new PaymentRequest
            {
                Amount = amount,
                Currency = currency,
                GatewayId = gatewayId,
                CustomerId = customerId,
                ReturnUrl = returnUrl,
                CancelUrl = cancelUrl
            };

            return await _client.Payments.CreateAsync(request);
        }

        public async Task<PaymentResponse> ProcessPaymentResponseAsync
        (string paymentId, string gatewayId)
        {
            return await _client.Payments.ProcessAsync(paymentId, gatewayId);
        }

        public async Task HandlePaymentErrorAsync(string paymentId, PaymentError error)
        {
            await _client.Payments.SetErrorAsync(paymentId, error);
        }
    }
}
  1. In your ASP.NET Core application, use the payment service to create payment requests, redirect the user to the payment gateway, and process payment responses.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using Microsoft.AspNetCore.Mvc;

namespace Ecommerce.Web.Controllers
{
    public class PaymentController : Controller
    {
        private readonly PaymentService _paymentService;

        public PaymentController(PaymentService paymentService)
        {
            _paymentService = paymentService;
        }

        [HttpGet]
        public async Task<IActionResult> Checkout(string gatewayId, decimal amount,
         string currency, string customerId, string returnUrl, string cancelUrl)
        {
            var request = await _paymentService.CreatePaymentRequestAsync(gatewayId, 
            amount, currency, customerId, returnUrl, cancelUrl);
            return Redirect(request.RedirectUrl);
        }

        [HttpGet]
        public async Task<IActionResult> Complete(string paymentId, string gatewayId)
        {
            var response = await _paymentService.ProcessPaymentResponseAsync(paymentId, gatewayId);
            if (response.Success)
            {
                // Update the order status and redirect to the order confirmation page
                return RedirectToAction("Confirmation", "Order", new { orderId = response.OrderId });
            }
            else
            {
                // Display an error message and redirect to the checkout page
                TempData["Error"] = response.Error.Message;
                return RedirectToAction("Checkout", "
                // Handle payment error
                await _paymentService.HandlePaymentErrorAsync(paymentId, response.Error);
                return RedirectToAction("Checkout", "Cart");
            }
        }

        [HttpGet]
        public async Task<IActionResult> Cancel(string paymentId, string gatewayId)
        {
            var error = new PaymentError
            {
                Code = "USER_CANCELED",
                Message = "The user cancelled the payment."
            };

            await _paymentService.HandlePaymentErrorAsync(paymentId, error);
            return RedirectToAction("Checkout", "Cart");
        }
    }
}

In this example, the PaymentController has three actions: Checkout, Complete, and Cancel.

The Checkout action is called when the user initiates the payment process, and it creates a payment request using the PaymentService and redirects the user to the payment gateway.

The Complete action is called when the user is redirected back to the application after completing the payment, and it processes the payment response using the PaymentService.

If the payment was successful, it updates the order status and redirects the user to the order confirmation page. If the payment was not successful, it displays an error message and redirects the user back to the checkout page.

The Cancel action is called when the user cancels the payment, and it handles the payment error by calling the HandlePaymentErrorAsync method of the PaymentService.

Leveraging machine learning to personalize the shopping experience with Azure ML and .NET

Here is an example of a C# microservice that leverages machine learning to personalize the shopping experience with Azure ML and .NET:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using Microsoft.Azure.CognitiveServices.Personalizer;
using Microsoft.Azure.CognitiveServices.Personalizer.Models;

namespace Ecommerce.Web.Services
{
    public class PersonalizationService
    {
        private readonly PersonalizerClient _client;

        public PersonalizationService(string endpoint, string apiKey)
        {
            _client = new PersonalizerClient(new ApiKeyServiceClientCredentials(apiKey))
            {
                Endpoint = endpoint
            };
        }

        public async Task<RankedAction> GetNextActionAsync(string context, IEnumerable<Action> actions)
        {
            var request = new RankRequest
            {
                ContextFeatures = JsonConvert.DeserializeObject<List<ContextFeature>>(context),
                Actions = actions
            };

            return await _client.RankAsync(request);
        }

        public async Task RewardAsync(string eventId, double value)
        {
            await _client.RewardAsync(eventId, value);
        }

        public async Task<IEnumerable<Product>> GetRecommendedProductsAsync(string customerId, int count)
        {
            var context = new
            {
                CustomerId = customerId
            };

            var actions = _productService.GetAll().Select(p => new Action
            {
                Id = p.Id.ToString(),
                Features = new List<Feature>
                {
                    new Feature("Category", p.Category),
                    new Feature("Price", p.Price)
                }
            });

            var rankedActions = await _personalizationService.GetNextActionAsync(
                JsonConvert.SerializeObject(context), actions);
            return rankedActions.Actions.Take(count).
                    Select(a => _productService.GetById(Guid.Parse(a.Id)));
        }
    }
}

In this example, the PersonalizationService class takes the endpoint and API key of the Azure ML Personalizer service as arguments in the constructor. It uses these to create a PersonalizerClient object, which it uses to perform various operations. The GetNextActionAsync method takes a context and a list of actions as input, and returns a ranked list of actions based on their predicted score.

In this example, the GetRecommendedProductsAsync method uses the PersonalizationService to get a ranked list of products based on the customer’s past interactions and preferences. It does this by defining the customer’s ID as the context and the products as the actions, and calling the GetNextActionAsync method of the PersonalizationService. It then returns the top count products from the ranked list.

This is just a simple example of how you can use Azure ML Personalizer and .NET to personalize the shopping experience for your customers. You can use a variety of context features and action features to tailor the recommendations to your specific use case.

You can also use the RewardAsync method of the PersonalizationService to provide feedback on the effectiveness of the recommendations and improve the accuracy of the model over time.

Deploying to Azure Kubernetes Service (AKS)

To deploy the Payment Service microservices to AKS (Azure Kubernetes Service) on Azure, you will need to follow the steps below:

  • Create an Azure Kubernetes Service cluster. You can do this using the Azure portal, Azure CLI, or Azure PowerShell.
  • Create a Docker image of each microservice. You can do this by writing a Dockerfile for each microservice, and using the docker build command to build the image.
  • Push the Docker images to a container registry. You can use Azure Container Registry or a registry such as Docker Hub.
  • Create a deployment manifest for each microservice. A deployment manifest is a YAML file that specifies the details of the deployment, such as the number of replicas and the container image to use.
  • Use the kubectl command-line tool to deploy the microservices to the AKS cluster. You can do this by using the kubectl apply command and specifying the deployment manifest file.

Here is an example of a deployment manifest for a microservice:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  labels:
    app: payment-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: payment-service
  template:
    metadata:
      labels:
        app: payment-service
    spec:
      containers:
        - name:
          image: myregistry.azurecr.io/payment-service:latest
          ports:
            - containerPort: 80
          env:
            - name: PaymentService__Endpoint
              value: "https://myservice.azurewebsites.net"
            - name: PaymentService__ApiKey
              value: "abcdefghijklmnopqrstuvwxyz"

In this example, the deployment manifest specifies that there should be one replica of the payment-service microservice, and it should use the payment-service image from the specified container registry. It also specifies the environment variables that should be passed to the container, such as the endpoint and API key for the payment service.

Once you have created the deployment manifests and pushed the Docker images to the container registry, you can use the kubectl apply command to deploy the microservices to the AKS cluster:

1
2
kubectl apply -f payment-service-deployment.yaml
kubectl apply -f personalization-service-deployment.yaml

This will deploy the microservices to the AKS cluster, and they will be accessible via the cluster’s internal network. You can then create a load balancer or use an ingress controller to expose the microservices to the public internet.